How to pass parameters to a constructor? - c++

I've got a class A, which consists of objects B and C. How to write a constructor of A that gets B and C objects? Should I pass them by value, by (const) reference, or a pointer? Where should I deallocate them?
I thought about pointers, because then I could write:
A a(new B(1,2,3,4,5), new C('x','y','z'))
But I don't know whether it's a good practice or not. Any suggestions?

Usually you pass by const reference:
A a(B(1,2,3,4,5), C('x','y','z'))
No need for pointers here.
Usually you store values unless copying is too inefficient.
The class definition then reads:
class A {
private:
B b;
C c;
public:
A(const B& b, const C& c): b(b), c(c) { }
};

Should I pass them by value, by (const) reference, or a pointer?
By const reference if object is big
by value if object is small
by const pointer if it is an optional argument that can be zero (i.e. "NULL")
by pointer if it is an optional argument that can be zero but will be owned (i.e. deallocated) by constructed class.
Please note that if your class have internal instances of B and C, then passing them by reference, value or const reference, will most likely involve using copy constructor or assignment operator. Which won't be necessary with pointers.
A a(new B(1,2,3,4,5), new C('x','y','z'))
Normally(i.e. not always) it is a bad idea, because:
if A doesn't deallocate arguments, you have a memory leak.
If A takes ownership of arguments and deallocates them, then you won't be able to pass values allocated on stack as arguments. Still, depending on your code design this may be acceptable (Qt 4 frequently takes ownership of objects created with new)
Where should I deallocate them?
The best idea is to make sure that compiler deallocates arguments automatically for you.
This means passing by reference, const reference or by value. Or using smart pointers.

What you pass in depends on your needs.
Do you need a copy of the thing you are passing in? Then pass by const-reference.
struct A
{
A(const B& b, const C& c) : m_b(b), m_c(c) {}
private:
B m_b;
C m_c;
};
And construct it like this:
A myA(B(1,2,3), C(4,5,6));
If you want your A object to refer to some other B and C objects (but not own them) then use pointers (or possibly references).

Edit: The examples given here do not respect the rule of the Big Three (thanks #Philipp!). If the definition of A is used as given below, the code will crash on copy construction for A, or on assignment for A. To define the code correctly, the assignment operator and copy constructor should be explicitly defined for A (or explicitly forbidden - declared as private and never implemented). (end Edit)
Should I pass them by value, by
(const) reference, or a pointer?
If A uses B and C, then hold them by reference or pointer inside of A. To choose between reference and pointer, see how B and C are allocated.
If they are local stack objects constructed in the same scope as A, then pass them by const reference.
If they are dynamically allocated objects that A uses, make A own them: pass them by pointers, and have A's destructor delete them.
If they are optional components of A, pass them by pointer (that can be null).
If A is not responsible of deleting them, pass them by * const.
Where should I deallocate them?
Usually where you no longer need them :).
If they are needed past the scope of A (if they are external objects that A uses) then delete them when A's scope is complete.
If they are owned by A, delete them in the destructor for A. It may make sense to also delete them during the lifetime of A, if the pointers should be changed.
Here's an example, where B is a replaceable component injected into A (and owned by A) and C is an optional component owned by A (but injected into A also).
("owned by" means A is responsible for deleting both objects)
class B;
class C;
class A
{
B* b;
C* c;
public:
A(B* const bb, C* const cc = 0) // cc is optional
: b(bb), c(cc)
{
}
void resetB(B* const bb = 0)
{
delete b;
b = bb;
}
~A()
{
resetB();
delete c;
}
};
{
A a(new B, new C);
a.resetB(); // delete B
a.resetB(new B); // delete former B and set a new one
} // both members of A are deleted
But I don't know whether it's a good
practice or not. Any suggestions?
It's up to you really, but you can write A a(B(1, 2, 4), C(1, 2, 3)) as easy as A a(new B(1, 2, 4), new C(1,2,3)); (in the former case - the one without new - the A::b and A::c should be references or objects/values inside the class, and A should not delete them at all).
The question should not be if you want to write the statement with dynamic allocation for B and C but if you need to. Dynamic allocation is slow and if you don't have a requirement for it you shouldn't do it.

Related

Is there any way can help code return value is const reference?

Suppose I have a class A, the class is copyable, but it will take a lot to copy it.
Suppose I have a class B, it can return a const reference of A.
class B
{
public:
...
const A& obtainA() const
{
return a;
}
private:
A a;
};
When I want to use A from B, I think the best practice is accessed A in B by const reference
B b;
const A& a = b.obtainA(); // do not needs to the heavy copy operation of A, good.
However, I always forget the const reference, my code looks like follow.
B b;
A a = b.obtainA(); // leads to the heavy copy operation of A, not good
It not only leads to the heavy copy operation but also the unsafety.
If the a call the non-const member function by mistake, it will leads to the member a in b be changed out of class.
Is there exists any way can help me to return const reference?
I want something like, if not returned by reference, the code can not be compiled.
Or any other advice is OK.
Thanks for your time.
Concrete applications
A in my application is the shared array. The data stored in the array is shared, it just something like the std::shared_ptr, but manage array of object but not single object.
The array is designed can be shared to reduce the copy overhead. The A is copyable because the array should be copyable.
The array is a widely used class, thus it is often a member of Array's user, that is the B in this question.
You could make A non-copyable, and provide a method to do the copy explicitly.
class A {
private:
A(A const &); // expensive copy
public:
A make_copy() { return *this; }
};
The make_copy method will create the expensive copy, but other code will no be able to make copies implicitly, since the copy-constructor is private.
If you do not want an object to be modified, make the object itself constant:
B const b;
A a = b.obtainA(); // nope, not allowed
I personally believe that everything should be constant unless there is a good reason for it not to be.

calling copy constructor and operator= for class data members

Below is an example code (for learning purpose only). Classes A and B are independent and have copy contructors and operators= .
class C
{
public:
C(string cName1, string cName2): a(cName1), b(new B(cName2)) {}
C(const C &c): a(c.a), b(new B(*(c.b))) {}
~C(){ delete b; }
C& operator=(const C &c)
{
if(&c == this) return *this;
a.operator=(c.a);
//1
delete b;
b = new B(*(c.b));
//What about this:
/*
//2
b->operator=(*(c.b));
//3
(*b).operator=(*(c.b));
*/
return *this;
}
private:
A a;
B *b;
};
There are three ways of making assignment for data member b. In fact first of them calls copy constructor. Which one should I use ? //2 and //3 seems to be equivalent.
I decided to move my answer to answers and elaborate.
You want to use 2 or 3 because 1 reallocated the object entirely. You do all the work to clean up, and then do all the work to reallocate/reinitialized the object. However copy assignment:
*b = *c.b;
And the variants you used in your code simply copy the data.
however, we gotta ask, why are you doing it this way in the first place?
There are two reasons, in my mind, to have pointers as members of the class. The first is using b as an opaque pointer. If that is the case, then you don't need to keep reading.
However, what is more likely is that you are trying to use polymorphism with b. IE you have classes D and E that inherit from B. In that case, you CANNOT use the assignment operator! Think about it this way:
B* src_ptr = new D();//pointer to D
B* dest_ptr = new E();//pointer to E
*dest_ptr = *src_ptr;//what happens here?
What happens?
Well, the compiler sees the following function call with the assignment operator:
B& = const B&
It is only aware of the members of B: it can't clean up the no longer used members of E, and it can't really translate from D to E.
In this situation, it is often better to use situation 1 rather than try to decern the subtypes, and use a clone type operator.
class B
{
public:
virtual B* clone() const = 0;
};
B* src_ptr = new E();//pointer to D
B* dest_ptr = new D();//pointer to E, w/e
delete dest_ptr;
dest_ptr = src_ptr->clone();
It may be down to the example but I actually don't even see why b is allocated on the heap. However, the reason why b is allocate on the heap informs how it needs to be copied/assigned. I think there are three reasons for objects to be allocated on the heap rather than being embedded or allocated on the stack:
The object is shared between multiple other objects. Obviously, in this case there is shared ownership and it isn't the object which is actually copied but rather a pointer to the object. Most likely the object is maintained using a std::shared_ptr<T>.
The object is polymorphic and the set of supported types is unknown. In this case the object is actually not copied but rather cloned using a custom, virtual clone() function from the base class. Since the type of the object assigned from doesn't have to be the same, both copy construction and assignment would actually clone the object. The object is probably held using a std::unique_ptr<T> or a custom clone_ptr<T> which automatically takes care of appropriate cloning of the type.
The object is too big to be embedded. Of course, that case doesn't really happen unless you happen to implement the large object and create a suitable handle for it.
In most cases I would actually implement the assignment operator in an identical form, though:
T& T::operator=(T other) {
this->swap(other);
return *this;
}
That is, for the actual copy of the assigned object the code would leverage the already written copy constructor and destructor (both are actually likely to be = defaulted) plus a swap() method which just exchanges resources between two objects (assuming equal allocators; if you need to take case of non-equal allocators things get more fun). The advantage of implementing the code like this is that the assignment is strong exception safe.
Getting back to your approach to the assignment: in no case would I first delete an object and then allocate the replace. Also, I would start off with doing all the operations which may fail, putting them into place at an appropriate place:
C& C::operator=(C const& c)
{
std::unique_ptr tmp(new B(*c.b));
this->a = c.a;
this->b = tmp.reset(this->b);
return *this;
}
Note that this code does not do a self-assignment check. I claim that any assignment operator which actually only works for self-assignment by explicitly guarding against is not exception-safe, at least, it isn't strongly exception safe. Making the case for the basic guarantee is harder but in most cases I have seen the assignment wasn't basic exception safe and your code in the question is no exception: if the allocation throws, this->b contains a stale pointer which can't be told from another pointer (it would, at the very least, need to be set to nullptr after the delete b; and before the allocation).
b->operator=(*(c.b));
(*b).operator=(*(c.b));
These two operations are equivalent and should be spelled
*this->b = *c.b;
or
*b = *c.b;
I prefer the qualified version, e.g., because it works even if b is a base class of template inheriting from a templatized base, but I know that most people don't like it. Using operator=() fails if the type of the object happens to be a built-in type. However, a plain assignment of a heap allocated object doesn't make any sense because the object should be allocated on the heap if that actually does the right thing.
If you use method 1 your assignment operator doesn't even provide the basic (exception) guarantee so that's out for sure.
Best is of course to compose by value. Then you don't even have to write your own copy assignment operator and let the compiler do it for you!
Next best, since it appears you will always have a valid b pointer, is to assign into the existing object: *b = *c.b;
a = c.a;
*b = *c.b;
Of course, if there is a possibility that b will be a null pointer the code should check that before doing the assignment on the second line.

Pass By Reference Questions

I'm fairly new to Pass By Reference, and I HAVE to make sure I understand this correctly. I have to convert all my Heap memory to Stack memory because my professor said so, and I'm stuck on two concepts.
What is the best way to store a reference in a class? I originally had member objects as non pointers, but noticed the deconstructor would be called on the member variable when the object (not member object) was popped off the stack. This makes me think it was a copy, and not actually a reference.
Here is an example of what I had originally:
class B
{
public:
B();
~B();
};
class A
{
private:
B b;
public:
A();
~A();
setB(B& bVar);
};
void A::setB(B& bVar)
{
b = bVar;
}
My solution was to change it to a pointer so it didn't call the deconstructor, but I'M NOT SURE IF THIS IS THE CORRECT WAY TO DO IT. Here was my solution:
class B
{
public:
B();
~B();
};
class A
{
private:
B* b;
public:
A();
~A();
setB(B& bVar);
};
void A::setB(B& bVar)
{
b = &bVar;
}
My second question is kind of related. I'm not sure what exactly happens when you have:
object1 = object2&.
Is object1 a copy or is it actually another identifier for object2?
References behave like symbolic aliases to instances, and are in some respects like "pointers" that can't (shouldn't) be null. For the sake of this explanation, I'll refer to them below as though they were pointers.
When you have a T&, it means that it is pointing to a T, and is not itself a copy.
When you have a T = T&, it means you'll get a copy (or a copy of a copy) depending on how the constructor or assignment operator are defined.
When you have an R& = L, it means you'll get copy of L into whatever the R& is pointing to (provided the assignment operator of R permits this).
Concerning the "correct" way of storing references, I would ask at least these questions:
Is it acceptable for the member reference to remain the same throughout the containing object's lifetime?
Will instances of the containing type always be destroyed before the object(s) pointed to by the member reference?
If both are true, then simply declaring and appropriately initializing a member T& should suffice:
class B
{
// details...
};
class A
{
B &_b;
public:
A(B &b) :
_b(b)
{}
};
Otherwise, despite the requirements imposed upon you, the situation might call for something like shared_ptr<> or similar.
References to objects living on the stack, in-turn held by other objects that themselves may be constructed in such a way that they will outlive their reference's lifespan are merely pointers waiting to dangle.
Consider copying, or arguing that heap-allocated memory is the better option.
If you are uncertain of the reference network induced by your program, you need to redesign it.
EDIT:
It is important to note that, when passing a reference to a function (const T& in particular), there are certain situations in which it can be elided by the compiler. For example: When such a function is inlined, references can be replaced by more efficient addressing logic than if they were required to be pointers.
In this respect, they are not pointers.

Can optional references be created in the new C++11?

Given the new C++11 standard and the move semantics introduced in it, could it be possible to create default values for constructor references? Here Default value to a parameter while passing by reference in C++ it is said that no, but perhaps the new standard allows some trickiness.
Basically what I want is to use a default object for the normal usage and to pass a mock object that records all the calls the host object has done in the testing phase. It should be something like
class A {
B& b;
public:
A(B & b = B()){} // This does not work
}
and when testing what I want is
BMock bMock;
A a(bMock);
bMock.getStatistics();
Any ideas?
How about this:
class Foo
{
B default_B;
public:
std::reference_wrapper<B> b;
Foo() : b(std::ref(default_B)) { }
Foo(B & br) b(std::ref(br)) { }
};
Here's an alternative idea that might be lighter-weight, at the expense of dynamic allocation in the default case:
#include <memory>
class Foo
{
std::unique_ptr<B> pB;
public:
std::reference_wrapper<B> b;
Foo() : pb(new B), b(std::ref(*pb)) { }
Foo(B & br) pb(), b(std::ref(br)) { }
};
Yes, the default initializer expression is a temporary object, and it will bind to an rvalue reference. However, you need to pass non-temporary objects through std::move to get them to bind to the reference.
Usually passing something through std::move indicates that it will be destroyed by the called function. The standard goes so far as to call the result of std::move an "expiring value;" although there's no real semantic necessity for it to expire, it's a pretty strong convention.
So, you can do this, but be careful.
Looking closer at your example, you want to keep a reference to b inside a, which means that there's nowhere to permanently store the proposed default value if no argument were used. You would be retaining a reference to a destroyed temporary. So unfortunately I can't really adapt your example…
Just an idea, what about this:
class A
{
std::shared_ptr<B> m_b;
public:
A() : m_b(new B) {}
A(B& b) : m_b(&b, [](B*){}) {}
};
On another note, I'm against storing off anything you take as a reference, I don't feel it connotes your usage at all. I'm also against members which are references, as they disallow assignment operators.

convert pointer to shared_ptr

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.