Reputation: 12372
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?
Upvotes: 8
Views: 29371
Reputation: 27365
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.
Upvotes: 1
Reputation: 26409
Should I pass them by value, by (const) reference, or a pointer?
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:
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.
Upvotes: 4
Reputation: 54270
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).
Upvotes: 2
Reputation: 49802
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) { }
};
Upvotes: 10