I have recently seen a question on stack overflow that how to get derived object from function,
some suggested that create local object and return copy from function. how about returning this from function?
I just wanna know, is that good coding practice?
Thank you for your assistance and time.
below is my example code.
class Base {
public:
virtual ~Base() {}
};
class Derived: public Base
{
private:
int i;
public:
Derived* func(int e) {
i = e;
return this;
}
int getI() { return i; }
};
You could use your code like this
Derived d;
Derived* d_ptr = d.func(123);
Seems easier to just write this (assuming a suitable constructor)
Derived x(123);
Derived* x_ptr = &x;
But maybe you were thinking of something else.
Derived d;
Derived* d_ptr = d.func(123);
why not d_ptr = &d;
whey d.func returns this? when use d.func, user have the pointer of d. no need to return again. may be want to use in chain like d.func(1)->func(2)->func(3)
Several operators used to return self reference (but not pointer):
copy/move assignment
pre increment/decrement
operator +=, operator -=, ...
mainly to mimic built-in behavior.
That allows to chain operation: a = b = c = 42; (instead of c = 42; b = c; a = b;).
(Abusing of) chaining is not necessary more readable, and split in several statements may be clearer.
The pro-chaining also apply it to setter:
rectangle.set_height(42).set_width(21).set_position(x, y);
About pointer versus reference, returning pointer implies generally that nullptr is possible value (else reference is better).
operators which might return pointer are (address of) operator& and arrow operator->.
Behavior of default & already returns this, so no need to overload it to return this.
operator-> should, at the end, returns a pointer; this might be a valid choice depending of the wrapper class.
Related
Suppose i have this sample code:
class A
{
public:
static void* operator new(size_t sz);
private:
int xA;
float yA;
};
class B : public A
{
private:
int xB;
float yB;
};
void* A::operator new(size_t sz)
{
void* ptr = (void*)new B();
return ptr;
}
int main()
{
B* b = (B*) new A();
// Use b ..
delete b;
return 0;
}
Here the constructors will be called in that order (tested in VS2012):
A constructor
B constructor
A constructor
The first two constructors calls are because of the new B() in the overloaded operator new function.
But then the A constuctor will be called again on the pointer returned by the function because the overloaded operator new is supposed to return a pointer to free memory (without creating the object), so the constructor is called again.
If i use the pointer b in this example, is this undefined behaviour?
The code you posted has endless recursion, since you call
A::operator new from within A::operator new; class B
inherits the operator new from A.
Beyond that, you lie to the compiler, which results in undefined
behavior. After new A, you have a pointer to an object whose
type is A. You can legally convert its address to a B*, but
all you can do with that B* is convert it back to an A*;
anything else is undefined behavior.
And it's not clear what you're trying to achieve with the new
B in A::operator new. The compiler will consider any memory
returned from an operator new as raw memory; in this case, it
will construct an A object in it, and from then on out, all
you have is an A object. Any attempt to use it as a B
object is undefined behavior. (And of course, if you actually
need to destruct the B created in A::operator new, you can't
because you've overwritten it.
Finally: you don't have to declare operator new as static;
it implicily is, and it's idiomatic not to write the static in
this case. Similarly, when assigning the results of new B to
a void*, the conversion is idiomatic, and it is idiomatic not
to make it explicit. (It's also best to avoid the C style
casts, since they hide too many errors.)
In general , operator new() should not CREATE an object, it should create space for an object. Your code will overwrite a B object with an A object, and then use it as a B object, and yes, that would be "undefined" (probably covered in the docs under "casting an object to a different type that it wasn't originally created as).
This may appear to work in this particular case, but if the constructor of B is more complex (e.g. there are virtual functions in B), it would immediately fail to work correctly.
If you want to allocate memory for an object, you could do:L
void* A::operator new(size_t sz)
{
void* ptr = (void*)::new unsigned char[sz];
return ptr;
}
Now you are not calling two different constructors for the same object!
The contract of operator new is just the memory allocation, the initialization is done later by the new-expression (by calling the constructor) or by program code if you call the operator directly.
What you are trying to do cannot be done, not like that. You could redesign to use a factory member function that would return a pointer to a B object, for example...
class A
{
public:
A* operator->() const
{
}
void Test() {}
};
then call it like this.
A* a = new A;
a->Test();
The code builds and runs successfully in VC2010. It seems very strange. I am wondering it is by design or it is a bug of VC2010?
Thanks
You aren't calling your operator-> in your example, you are calling Test directly from an A*. You want:
(*a)->Test();
Or...
A a;
a->Test();
There's nothing wrong with VS2010 concerning operator-> (that I know of).
Using -> on a pointer named a effectively executes: (*a).. Using -> on a variable by value will invoke your operator-> if present, or be a syntax error if there is no operator->.
Your code is:
A* a = new A;
a->Test();
The "a" is a pointer to an A. It is NOT an A object itself, it is a memory address of the A object on the heap.
When you call a->Test() you invoke the pointer's -> operator (built in for all pointer types in C++). You would have to do this to invoke your operator:
//Create an A (NOT a pointer).
A a;
//Invoke the A's operator ->
a->Test();
Which is how STL iterators work - they're class types, not pointers to class types. Note that the return type of operator -> must make sense for the operation/member you're trying to invoke.
So, here's an example that would call test via the ->:
#include <iostream>
class A
{
public:
A* operator->()
{
return this;
}
void Test() { std::cout << "Hello World!"; }
};
int main()
{
A a;
a->Test();
}
It's strange, but it works because a->Test(); returns the current object, which Test() is then called on (see the return this; line).
See STL iterators for useful examples of why you'd actually want to do this.
I have the following contrived example (coming from real code):
template <class T>
class Base {
public:
Base(int a):x(a) {}
Base(Base<T> * &other) { }
virtual ~Base() {}
private:
int x;
};
template <class T>
class Derived:public Base<T>{
public:
Derived(int x):Base<T>(x) {}
Derived(Derived<T>* &other): Base<T>(other) {}
};
int main() {
Derived<int> *x=new Derived<int>(1);
Derived<int> y(x);
}
When I try to compile this, I get:
1X.cc: In constructor ‘Derived<T>::Derived(Derived<T>*&) [with T = int]’:
1X.cc:27: instantiated from here
1X.cc:20: error: invalid conversion from ‘Derived<int>*’ to ‘int’
1X.cc:20: error: initializing argument 1 of ‘Base<T>::Base(int) [with T = int]’
1) Clearly gcc is being confused by the constructors. If I remove the reference
from the constructors, then the code compiles. So my assumption is that something goes wrong
with up-casting pointer references. Can someone tell me what is going on here?
2) A slightly unrelated question. If I were to do something horrendous like "delete other" in the constructor (bear with me),
what happens when someone passes me a pointer to something on the stack ?
E.g. Derived<int> x(2);
Derived<int> y(x);
where
Derived(Derived<T>*& other) { delete other;}
How can I make sure that pointer is legitimately pointing to something on the heap?
Base<T> is a base type of Derived<T>, but Base<T>* is not a base type of Derived<T>*. You can pass a derived pointer in place of a base pointer, but you can't pass a derived pointer reference in place of a base pointer reference.
The reason is that, suppose you could, and suppose the constructor of Base were to write some value into the reference:
Base(Base<T> * &other) {
Base<T> *thing = new Base<T>(12);
other = thing;
}
You've just written a pointer to something which is not a Derived<T>, into a pointer to Derived<T>. The compiler can't let this happen.
You cannot convert a reference to a pointer to Derived to a reference to a pointer to Base. (Templates don't contribute to the issue here, so removed from my example below.)
If you want to defer responsibility for a pointer, use a smart pointer type. Smart pointer types can represent the "responsibility to delete" that raw pointers cannot. Examples include std::auto_ptr and boost::shared_ptr, among many others.
Why you cannot upcast pointer references:
struct Base {};
struct Derived : Base {};
struct Subclass : Base {};
int main() {
Derived d;
Derived* p = &d;
Derived*& d_ptr = p;
Base*& b_ptr = d_ptr; // this is not allowed, but let's say it is
Base b;
b_ptr = &b; // oops! d_ptr no longer points to a Derived!
Subclass s;
b_ptr = &s; // oops! d_ptr no longer points to a Derived!
}
When you pass your 'other' parameter to the Base ctor, you're trying to do the same thing as b_ptr = d_ptr above.
You make sure that pointer points to something on the heap by writing that in your documentation and relying on the caller to abide by that. If whoever calls your constructor passes a stack pointer, all bets are off, and it's not your fault - you can try to catch the problem early, but no guarantees.
That's how the standard library works - often it'll catch obvious errors, but it's not required to, and it's up to the caller to make sure they're not doing anything stupid.
Your x variable is not a pointer, it should be if you want to assign a new Derived<int> to it.
As for deleting things on the stack, don't do it. There is no way to tell whether you have been passed the address of something on the stack or on the heap (indeed, the C++ standard doesn't even acknowledge the existence of a stack). The lesson here is that you shouldn't be deleting things that you don't own, especially if you have no way of telling where they came from.
Not sure why do you want reference to the pointer. Why not
Base(Base<T> * other) { }
and
Derived(Derived<T>* other): Base<T>(other) {}
That should work.
And, like other answered, I don't think you can legitimately know whether the pointer is pointing into heap.
Edit: why can't one do what you're trying to: consider example:
Derived1<int> *x = new Derived1<int>
Base<int> **xx =&x;
Derived2<int> y;
*xx = &y;
Where Derived1 and Derived2 are different classes derived from Base? Would you think it's legitimate? Now that x of type Derived1* points to Derived2?
I have some library code (I cannot not change the source code) that returns a pointer to an object (B). I would like to store this pointer as shared_ptr under a class with this type of constructor:
class A
{
public:
A(boost::shared_ptr<B> val);
...
private:
boost::shared_ptr<B> _val;
...
};
int main()
{
B *b = SomeLib();
A a(b); //??
delete b;
...
}
That is, I would like to make a deep-copy of b and control its life-time under a (even if original b is deleted (delete b), I still have an exact copy under a).
I'm new to this, sorry if it seems trivial...
If the library defines this B object, the library should provide (or outright prohibit) the mechanism for copying B.
As a sidenote,
If your class A is exclusively controlling the lifetime of this copied object, the smart pointer you really want to use is boost::scoped_ptr.
boost::shared_ptr is named after its ability to share lifetime responsibility, which it sounds like you don't want. scoped_ptr won't let that accidentally happen.
As you say, you have to copy them not just copy a pointer. So either B already has implemented 'clone' method or you have to implement some external B* copy(B* b) which will create new B with same state.
In case B has implemented copy constructor you can implement copy as just
B* copyOf(B* b)
{
return new B(*b);
}
In case B has implemented clone method or similar you can implement copy as
B* copyOf(B* b)
{
return b->clone();
}
and then your code will look like
int main()
{
B *b = SomeLib();
A a(copyOf(b));
delete b;
...
}
Deep-copying is implemented trivially in C++ by the copy constructor since in C++, all objects have value semantics by default. Copying in such a way doesn't work for polymorphous objects though – in such cases, you'd have to implement a virtually overridden clone method in your class.
But in all other cases, simply writing
A(boost::shared_ptr<B> val) : _val(new B(*val)) { }
will do.
#include "iostream"
class A {
private:
int a;
public :
A(): a(-1) {}
int getA() {
return a;
}
};
class A;
class B : public A {
private:
int b;
public:
B() : b(-1) {}
int getB() {
return b;
}
};
int main() {
std::auto_ptr<A> a = new A();
std::auto_ptr<B> b = dynamic_cast<std::auto_ptr<B> > (a);
return 0;
}
ERROR: cannot dynamic_cast `(&a)->std::auto_ptr<_Tp>::get() const
Well, std::auto_ptr<B> is not derived from std::auto_ptr<A>. But B is derived from A. The auto_ptr does not know about that (it's not that clever). Looks like you want to use a shared ownership pointer. boost::shared_ptr is ideal, it also provides a dynamic_pointer_cast:
boost::shared_ptr<A> a = new A();
boost::shared_ptr<B> b = dynamic_pointer_cast<B> (a);
For auto_ptr, such a thing can't really work. Because ownership will move to b. But if the cast fails, b can't get ownership. It's not clear what to do then to me. You would probably have to say if the cast fails, a will keep having the ownership - which sounds like it will cause serious trouble. Best start using shared_ptr. Both a and b then would point to the same object - but B as a shared_ptr<B> and a as a shared_ptr<A>
dynamic cast doesn't work that way. A : public B does not imply auto_ptr<A> : public auto_ptr<B>. This is why boost's shared_ptr provides shared_dynamic_cast. You could write an auto_ptr dynamic cast though:
template<typename R, typename T>
std::auto_ptr<R> auto_ptr_dynamic_cast(std::auto_ptr<T>& in) {
auto_ptr<R> rv;
R* p;
if( p = dynamic_cast<R*>( in.get() ) ) {
in.release();
rv = p;
}
return rv;
}
Just be aware of what happens here. Since auto_ptrs have ownership semantics, a successful downcast means the original more generally typed, auto_ptr no longer has ownership.
The reason is that auto_ptr is not actually a pointer. It's a smart pointer which is a pointer wrapper but not actually a pointer. The type that is passed as a template style argument to dynamic_cast must be a true pointer (or reference) type.
http://msdn.microsoft.com/en-us/library/cby9kycs(VS.80).aspx
You're trying to cast a A* (returned by a.get()) to std::auto_ptr<B>, and since the second is not even a pointer type this fails. Probably you just want to cast it to B*:
std::auto_ptr<A> a(new A());
std::auto_ptr<B> b(dynamic_cast<B*>(a.get()));
This will still not compile, because A and B aren't polymorphic types. A needs to have a virtual function in order to make the types polymorphic. This will compile, but the cast will just throw std::bad_cast, since it isn't really a B*.
And even if it were a B*, it will fail in horrendous ways if you try to use it. Both std::auto_ptrs a and b will assume they own the object and free it later on, resulting in all kinds of memory corruption. You probably want to use a.release() after the cast was successful.
I think c++ stores RTTI (run time type information) in the vtable. Hence to use dynamic_cast<> with an instance object, the object needs have 'vtable'. C++ creates vtable only when at least one function is declared 'virtual' in the class.
The class A and Class B there are no virtual functions. This could be reason for the dynamic_cast failure. Try declaring a virtual destructor in base class.