I want to write some unit tests of a library I'm writing
I have a class which looks like this one :
class A
{
public:
A(B* pB)
// construction details, involves my library
// but ultimately there is a new being done ,)
B* m_pB;
};
I'd like to check that the pointer m_pB is actually initialized, so I did something along these lines :
A* p = // creation of this object involves my library
BOOST_REQUIRE( p->m_pB != NULL );
but it happens g++ does not zero-initialize the memory, so the value of p->m_pB is just plain random. Is there a way to force g++ to zero initialize this memory for me when I new the object?
I believe Visual Studio does something similar with specific codes dependeing on where the memory is allocated.
edit: I can think of 2 backup solutions right now: using a smart pointer, or writing a new operator ...
Simply implement the default constructor. This guarantees that without passing an argument, the pointer is initialized to NULL.
class A
{
public:
A(B* pB)
// construction details, involves my library
// but ultimately there is a new being done ,)
A() : m_pB(NULL) {}
B* m_pB;
};
Or as Fritschy points out:
A() : m_pB() {}
Use an always-initializing class.
template<typename T> class always_initialized {
T t;
public:
operator T&() { return t; }
operator const T&() const { return t; }
always_initialized() : t() {}
always_initialized(const T& ref) : t(ref) {}
};
Edit: I see that most people didn't understand what this actually does. If you just set the pointer to NULL, then you have to do that separately in every constructor, and then you have to do that again for every variable, and it's also not generic for other POD things like POD structs. always_initialized is more maintainable, as you're not repeating yourself, more concise, and more generic, as it's good for any POD type or even non-POD type.
Did you consider making m_pB private and always initializing it in your constructors? By using encapsulation to enforce your class invariants you don't even need to do the kinds of checks you're implementing here.
Thanks for your answers, but I'd like a less invasive technique, as the classes are part of the test, and their constructor is right in the midle of the subject which is dependency injection.
I was just hopping for something similar to visual studio which sets the memory to some specific value in debug mode (I think?), through an option of g++ or something alike.
some answers/comments basically fall back to saying "don't test it, just don't make the mistake"
Finally, I've overloaded the new operator and added a call to memset(ptr, 0, size);
and I get my critical check p->m_pB != __null failed, it works fine.
you all get a +1 anyway, especially DeadMg for the interesting solution
Related
I have the following code snippet:
#include <iostream>
using namespace std;
class A {
int* data;
int size;
public:
A(int s):size(s)
{
data = new int[size];
}
A() {
data = nullptr;
}
~A() {
if (data) delete [] data;
}
};
class B {
A a[2];
public:
B() {
a[0] = A(10);
a[1] = A(11);
}
};
int main(int argc, char *argv[]) {
B b;
}
In the C++ code above, I have class A which has an array member int* data, and the (de)allocation of memory are handled by (de)constructor. The I created class B which has an array of class A of fixed length as a data member.
My question is: how to elegantly initialise the member A a[2]? In the code above, the A(10) and A(11) are created on the stack, when jumping out of the scope, their destructors will be called, hence the data comes invalid. When jumping of the main function's scope, the pointers held by a[2] will be deallocated twice, causing the error:
pointer being freed was not allocated.
One possible solution is to carefully design a copy constructor and a move constructor, by doing so the above coding paradigm could work.
Another solution I've tried is to initialise the array in the initialization list of class B:
B() : a { A(10), A(11) }
This solution works and I don't really tell the underlying mechanism of initialization list. I think it must be quite different from simply construct and copy. I really expected some experts could give an elaborate explanation of this mechanism. Of course, this solution is ugly hard-coded and not flexible.
So I wonder if there are some programming paradigms in C++ to tackle this design problem?
In the code above, the A(10) and A(11) are created on the stack
They are temporary objects. It is not specified where they are created or if they're created at all.
when jumping out of the scope, their destructors will be called
The destructor of each temporary will be called after the corresponding move assignment statement ends.
One possible solution is to carefully design a copy constructor and a move constructor, by doing so the above coding paradigm could work.
And {copy,move} assignment operator too. You should always do that when the implicitly declared ones don't do the right thing. And they never do the right thing if you delete something in the destructor.
Another solution I've tried is to initialise the array in the initialization list of class B
This solution works and I don't really tell the underlying mechanism of initialization list. I think it must be quite different from simply construct and copy.
The bug in the original code is badly behaving move assignment operator of A. Since the initialization list never move assigns from a temporary, it never triggers the bug.
This is actually the more elegant way to construct a that you asked for. Not because it avoids the bug, but because avoiding unnecessary moving is good thing, intrinsically.
So I wonder if there are some programming paradigms in C++ to tackle this design problem?
Yes. RAII and Single responsibility principle. Unless your class does nothing else, besides managing the memory pointed by data, it should not be managing the memory. Instead, it should delegate the memory management to a RAII object. In this case, you should use a std::vector member.
class A {
std::vector<int> data;
public:
A(int s):data(s) {}
A() = default;
};
Using an initializer list to construct B::a, like this:
class B {
A a[2];
public:
B() : a({10, 11}){
}
};
The ideal answer would be to force A to use movements instead of copies, or on a copy to allocate new space for the item. Of the two, the most efficient is the former and so I will expand on it below:
Forcing movement can be done in two fashions:
Delete the copy constructor and copy operator=, and implement your own move constructor and operator=
Consistently use std::move and std::swap.
Of these, the former is superior in that you will be unable to accidentally copy the class, but with the latter the fact that you are moving will be more evident.
To delete the default copy methods do:
class A {
A( const A& a ) = delete;
A& operator =( const A& a ) = delete;
}
As mentioned here you can use reference (d-reference) instead of pointer (d-pointer) in case of PIMPL idiom.
I'm trying to understand if there are any serious issues with this implementation and what are the pros and cons.
Pros:
Shorter syntax because of usage of "." instead of "->".
...
Cons:
What if the new ObjectPivate() fails and new doesn't throw (e.g.: new(std::nothrow) or custom new) and returns nullptr instead? You need to implement additional stuff to check if the referance is valid. In case of pointer you just use:
if (m_Private)
m_Private->Foo();
In rare case of multiple constructors for the Object with complex initialisation logic the solution could be not applicable. [© JamesKanze]
It fills more natural to use pointer for memory management. [© JamesKanze]
Some additional implementation details needs to be considered (use of swap()) to ensure the exception-safety (e.g. implementation of assignment operator) [© Matt Yang]
...
Here the sample code for illustration:
// Header file
class ObjectPrivate;
class Object
{
public:
Object();
virtual ~Object();
virtual void Foo();
private:
ObjectPrivate& m_Private;
};
// Cpp file
class ObjectPrivate
{
public:
void Boo() { std::cout << "boo" << std::endl; }
};
Object::Object() :
m_Private(* new ObjectPrivate())
{
}
Object::~Object()
{
delete &m_Private;
}
void Object::Foo()
{
m_Private.Boo();
}
It's really just a matter of style. I tend to not use
references in classes to begin with, so using a pointer in the
compilation firewall just seems more natural. But there's
usually no real advantage one way or the other: the new can
only fail by means of an exception.
The one case where you might favor the pointer is when the
object has a lot of different constructors, some of which need
preliminary calculations before calling the new. In this
case, you can initialize the pointer with NULL, and then call
a common initialization routine. I think such cases are rare,
however. (I've encountered it once, that I can recall.)
EDIT:
Just another style consideration: a lot of people don't like something like delete &something;, which is needed if you use references rather than pointers. Again, it just seems more natural (to me, at least), that objects managing memory use pointers.
It's not convenient to write exception-safe code I think.
The first version of Object::operator=(Object const&) might be:
Object& operator=(Object const& other)
{
ObjectPrivate *p = &m_Private;
m_Private = other.m_Private; // Dangerous sometimes
delete *p;
}
It's dangerous if ObjectPrivate::operator=(ObjectPrivate const&) throws exception. Then what about using a temporary variable? Aha, no way. operator=() has to be invoked if you want change m_Private.
So, void ObjectPrivate::swap(ObjectPrivate&) noexcept can act as our savior.
Object& operator=(Object const& other)
{
ObjectPrivate *tmp = new ObjectPrivate(other.m_Private);
m_Private.swap(*tmp); // Well, no exception.
delete tmp;
}
Then consider the implementation of void ObjectPrivate::swap(ObjectPrivate&) noexcept. Let's assume that ObjectPrivate might contain a class instance without swap() noexcept or operator=() noexcept. I think it's hard.
Alright then, this assumption is too strict and not correct sometimes. Even so, it's not necessary for ObjectPrivate to provide swap() noexcept in most cases, because it's usually a helper structure to centralize data.
By contrast, pointer can save a lot of brain cells.
Object& operator=(Object const& other)
{
ObjectPrivate *tmp = new ObjectPrivate(*other.p_Private);
delete p_Private;
p_Private = tmp; // noexcept ensured
}
It's much more elegant if smart pointers are used.
Object& operator=(Object const& other)
{
p_Private.reset(new ObjectPrivate(*other.p_Private));
}
Some quick and obvious additions:
Pro
The reference must not be 0.
The reference may not be assigned another instance.
Class responsibilities/implementation are simpler due to fewer variables.
The compiler could make some optimizations.
Con
The reference may not be assigned another instance.
The reference will be too restrictive for some cases.
I'd like to know is it better to specify a default initialization for a smart-pointer or do a NULL value check before accessing the smart-pointers methods?
Currently I've been using the method below to avoid calling increment() on a NULL pointer. Is this a reasonable way of doing things or is there a pitfall that I don't see?
Note: We use a custom smart-pointer class and I don't have the Boost libraries on my current configuration to test compile this code. This should compile, but YMMV.
Example.h
#include <boost/shared_ptr.hpp>
class Foo
{
public:
Foo() : mFoo(0) {}
Foo(int rawValue) : mFoo(rawValue) {}
void increment() { mFoo++; }
private:
int mFoo;
};
typedef boost::shared_ptr<Foo> FooSP;
class MyClass
{
public:
MyClass() : mFoo(new Foo()) {}
FooSP foo() { return mFoo; }
void setFoo(FooSP newFoo) { mFoo = newFoo; }
private:
FooSP mFoo;
};
Main.cpp
#include <Example.h>
int main()
{
MyClass temp; // Default-constructed
temp.foo()->increment(); // Increment Foo's member integer
// Before: mFoo = 0
// After: mFoo = 1
FooSP tempFoo = new Foo(10); // Create a Foo with a default size
temp.setFoo(FooSP(new Foo(10))); // Explicitly set the FooSP member
temp.foo()->increment(); // Increment the new FooSP
// Before: mFoo = 10
// After: mFoo = 11
return 0;
}
If you are using a smart pointer as a general replacement for a pointer type, you cannot get away from a check for null. This is because a class defined with a smart pointer with a default constructor is likely to allow the smart pointer to be created with its default constructor. Dynamically creating a new object just to fill the pointer until you can set it seems to be a waste of resources.
shared_ptr's constructor is explicit, so your initialization of tempFoo won't compile. If you wanted to save a line of code, you can avoid declaring the temporary like this:
temp.setFoo(FooSP(new Foo(10)));
You can also declare the method of setFoo to take a constant reference, to avoid manipulating the reference count when taking in the parameter.
void setFoo(const FooSP &newFoo) { mFoo = newFoo; }
Or use swap on the parameter instance.
void setFoo(FooSP newFoo) { std::swap(mFoo, newFoo); }
If I were required to implement something along the lines of what you are proposing, I would create a static instance of Foo to serve as the null version, and then have the increment method throw an exception if it was the null version.
class Foo
{
public:
static Foo Null;
//...
void increment() {
if (this == &Null) throw Null;
mFoo++;
}
//...
};
struct DeleteFoo {
void operator () (Foo *t) const {
if (t != &Foo::Null) delete t;
}
};
class MyClass
{
public:
MyClass() : mFoo(&Foo::Null, DeleteFoo()) {}
//...
};
Note the custom deleter for FooSP to properly deal with Foo::Null.
is it better to specify a default initialization for a smart-pointer or do a NULL value check before accessing the smart-pointers methods?
There is no right answer which applies to every case (more soon). If I had to err to one or the other, I would err toward NULL testing without default initialization because that's an obvious programmer error which can be detected and corrected easily.
However, I think the right answer is that there are good reasons we use multiple idioms for construction and initialization, and that you should choose the best approach for your program.
Typically, I will be explicit (no default or no default initialization) in the lower level classes, as well as complex higher level classes. When the classes are mid-level and defaults and ownership are more obvious (often because of limited use cases), then a default may be sensible.
Often, you will just want to be consistent, to avoid surprising clients. You'll also need to be aware of the complexity of allocating default-initialized objects. If it's big and complex to create, and a default does not make sense, then you are simply wasting a lot of resources when the default-constructed object is the wrong choice.
a) do not apply a default where it does not make sense. the default should be obvious.
b) avoid wasted allocations.
In addition to the approaches you have mentioned, there are a few other angles you might also consider:
Matching Foo's declared constructors in MyClass. At least, the ones which pertain to MyClass.
If copyable and efficient to copy, passing a Foo to MyClass's constructor.
Passing Foo in a container (smart pointer in this case) to MyClass's constructor to remove any ambiguity and to offer the client the option to construct (and share, in the case of a shared pointer) Foo as they desire.
Is this a reasonable way of doing things or is there a pitfall that I don't see?
Wasted allocations. Surprising results. It can restrict capabilities. The most obvious, broadly applicable problems are time and resource consumption.
To illustrate some scenarios:
say Foo reads a 1MB file every time it is constructed. when construction parameters are necessary and the default is not the right option, the file would have to be read a second time. the innocent default would double the disk io required.
in another case, an omitted construction parameter may be another large or complex shared pointer. if absent, Foo may create its own -- when the resource could/should have been shared.
Constructors parameters are often very important, and often should not be erased from the interface. It's certainly fine to do so in some cases, but these conveniences can introduce a lot of restrictions or introduce much unnecessary allocations and CPU time as the contained object's complexity increases.
Using both approaches in your programs is fine. Using additional approaches I outlined is also fine. Specifically, using the right approach for the problem is ideal - there are multiple ways to implement ideal solutions available; you just have to determine what that is in the context of what it is your program is trying to do. All these approaches have separate pros and cons - there is often an ideal match for the context of your program's operation and exposed interfaces.
The most interesting C++ question I've encountered recently goes as follows:
We determined (through profiling) that our algorithm spends a lot of time in debug mode in MS Visual Studio 2005 with functions of the following type:
MyClass f(void)
{
MyClass retval;
// some computation to populate retval
return retval;
}
As most of you probably know, the return here calls a copy constructor to pass out a copy of retval and then the destructor on retval. (Note: the reason release mode is very fast for this is because of the return value optimization. However, we want to turn this off when we debug so that we can step in and nicely see things in the debugger IDE.)
So, one of our guys came up with a cool (if slightly flawed) solution to this, which is, create a conversion operator:
MyClass::MyClass(MyClass *t)
{
// construct "*this" by transferring the contents of *t to *this
// the code goes something like this
this->m_dataPtr = t->m_dataPtr;
// then clear the pointer in *t so that its destruction still works
// but becomes 'trivial'
t->m_dataPtr = 0;
}
and also changing the function above to:
MyClass f(void)
{
MyClass retval;
// some computation to populate retval
// note the ampersand here which calls the conversion operator just defined
return &retval;
}
Now, before you cringe (which I am doing as I write this), let me explain the rationale. The idea is to create a conversion operator that basically does a "transfer of contents" to the newly constructed variable. The savings happens because we're no longer doing a deep copy, but simply transferring the memory by its pointer. The code goes from a 10 minute debug time to a 30 second debug time, which, as you can imagine, has a huge positive impact on productivity. Granted, the return value optimization does a better job in release mode, but at the cost of not being able to step in and watch our variables.
Of course, most of you will say "but this is abuse of a conversion operator, you shouldn't be doing this kind of stuff" and I completely agree. Here's an example why you shouldn't be doing it too (this actually happened:)
void BigFunction(void)
{
MyClass *SomeInstance = new MyClass;
// populate SomeInstance somehow
g(SomeInstance);
// some code that uses SomeInstance later
...
}
where g is defined as:
void g(MyClass &m)
{
// irrelevant what happens here.
}
Now this happened accidentally, i.e., the person who called g() should not have passed in a pointer when a reference was expected. However, there was no compiler warning (of course). The compiler knew exactly how to convert, and it did so. The problem is that the call to g() will (because we've passed it a MyClass * when it was expecting a MyClass &) called the conversion operator, which is bad, because it set the internal pointer in SomeInstance to 0, and rendered SomeInstance useless for the code that occured after the call to g(). ... and time consuming debugging ensued.
So, my question is, how do we gain this speedup in debug mode (which has as direct debugging time benefit) with clean code that doesn't open the possibility to make such other terrible errors slip through the cracks?
I'm also going to sweeten the pot on this one and offer my first bounty on this one once it becomes eligible. (50 pts)
You need to use something called "swaptimization".
MyClass f(void)
{
MyClass retval;
// some computation to populate retval
return retval;
}
int main() {
MyClass ret;
f().swap(ret);
}
This will prevent a copy and keep the code clean in all modes.
You can also try the same trick as auto_ptr, but that's more than a little iffy.
If your definition of g is written the same as in your code base I'm not sure how it compiled since the compiler isn't allowed to bind unnamed temporaries to non-const references. This may be a bug in VS2005.
If you make the converting constructor explicit then you can use it in your function(s) (you would have to say return MyClass(&retval);) but it won't be allowed to be called in your example unless the conversion was explicitly called out.
Alternately move to a C++11 compiler and use full move semantics.
(Do note that the actual optimization used is Named Return Value Optimization or NRVO).
The problem is occuring because you're using MyClass* as a magic device, sometimes but not always. Solution: use a different magic device.
class MyClass;
class TempClass { //all private except destructor, no accidental copies by callees
friend MyClass;
stuff* m_dataPtr; //unfortunately requires duplicate data
//can't really be tricked due to circular dependancies.
TempClass() : m_dataPtr(NULL) {}
TempClass(stuff* p) : m_dataPtr(p) {}
TempClass(const TempClass& p) : m_dataPtr(p) {}
public:
~TempClass() {delete m_dataPtr;}
};
class MyClass {
stuff* m_dataPtr;
MyClass(const MyClass& b) {
m_dataPtr = new stuff();
}
MyClass(TempClass& b) {
m_dataPtr = b.m_dataPtr ;
b.m_dataPtr = NULL;
}
~MyClass() {delete m_dataPtr;}
//be sure to overload operator= too.
TempClass f(void) //note: returns hack. But it's safe
{
MyClass retval;
// some computation to populate retval
return retval;
}
operator TempClass() {
TempClass r(m_dataPtr);
m_dataPtr = nullptr;
return r;
}
Since TempClass is almost all private (friending MyClass), other objects cannot create, or copy TempClass. This means the hack can only be created by your special functions when clearly told to, preventing accidental usage. Also, since this doesn't use pointers, memory can't be accidentally leaked.
Move semantics have been mentioned, you've agreed to look them up for education, so that's good. Here's a trick they use.
There's a function template std::move which turns an lvalue into an rvalue reference, that is to say it gives "permission" to move from an object[*]. I believe you can imitate this for your class, although I won't make it a free function:
struct MyClass;
struct MovableMyClass {
MyClass *ptr;
MovableMyClass(MyClass *ptr) : ptr(ptr) {}
};
struct MyClass {
MyClass(const MovableMyClass &tc) {
// unfortunate, we need const reference to bind to temporary
MovableMyClass &t = const_cast<MovableMyClass &>(tc);
this->m_dataPtr = t.ptr->m_dataPtr;
t.ptr->m_dataPtr = 0;
}
MovableMyClass move() {
return MovableMyClass(this);
}
};
MyClass f(void)
{
MyClass retval;
return retval.move();
}
I haven't tested this, but something along those lines. Note the possibility of doing something const-unsafe with a MovableMyClass object that actually is const, but it should be easier to avoid ever creating one of those than it is to avoid creating a MyClass* (which you've found out is quite difficult!)
[*] Actually I'm pretty sure I've over-simplified that to the point of being wrong, it's actually about affecting what overload gets chosen rather than "turning" anything into anything else as such. But causing a move instead of a copy is what std::move is for.
A different approach, given your special scenario:
Change MyClass f(void) (or operator+) to something like the following:
MyClass f(void)
{
MyClass c;
inner_f(c);
return c;
}
And let inner_f(c) hold the actual logic:
#ifdef TESTING
# pragma optimize("", off)
#endif
inline void inner_f(MyClass& c)
{
// actual logic here, setting c to whatever needed
}
#ifdef TESTING
# pragma optimize("", on)
#endif
Then, create an additional build configurations for this kind of testing, in which TESTING is included in the preprocessor definitions.
This way, you can still take advantage of RVO in f(), but the actual logic will not be optimized on your testing build. Note that the testing build can either be a release build or a debug build with optimizations turned on. Either way, the sensitive parts of the code will not be optimized (you can use the #pragma optimize in other places too, of course - in the code above it only affects inner_f itself, and not code called from it).
Possible solutions
Set higher optimization options for the compiler so it optimizes out the copy construction
Use heap allocation and return pointers or pointer wrappers, preferably with garbage collection
Use the move semantics introduced in C++11; rvalue references, std::move, move constructors
Use some swap trickery, either in the copy constructor or the way DeadMG did, but I don't recommend them with a good conscience. An inappropriate copy constructor like that could cause problems, and the latter is a bit ugly and needs easily destructible default objects which might not be true for all cases.
+1: Check and optimize your copy constructors, if they take so long then something isn't right about them.
I would prefer to simply pass the object by reference to the calling function when MyClass is too big to copy:
void f(MyClass &retval) // <--- no worries !
{
// some computation to populate retval
}
Just simple KISS principle.
Okay I think I have a solution to bypass the Return Value Optimization in release mode, but it depends on the compiler and not guaranteed to work. It is based on this.
MyClass f (void)
{
MyClass retval;
MyClass dummy;
// ...
volatile bool b = true;
if b ? retval : dummy;
}
As for why the copy construction takes so long in DEBUG mode, I have no idea. The only possible way to speed it up while remaining in DEBUG mode is to use rvalue references and move semantics. You already discovered move semantics with your "move" constructor that accepts pointer. C++11 gives a proper syntax for this kind of move semantics. Example:
// Suppose MyClass has a pointer to something that would be expensive to clone.
// With move construction we simply move this pointer to the new object.
MyClass (MyClass&& obj) :
ptr (obj.ptr)
{
// We set the source object to some trivial state so it is easy to delete.
obj.ptr = NULL;
}
MyClass& operator = (MyClass&& obj) :
{
// Here we simply swap the pointer so the old object will be destroyed instead of the temporary.
std::swap(ptr, obj.ptr);
return *this;
}
Consider the following class:
class A {
char *p;
int a, b, c, d;
public:
A(const &A);
};
Note that I have to define a copy constructor in order to do a deep copy of "p". This has two issues:
Most of the fields should simply be copied. Copying them one by one is ugly and error prone.
More importantly, whenever a new attribute is added to the class, the copy constructor needs to be updated, which creates a maintenance nightmare.
I would personally like to do something like:
A(const A &a) : A(a)
{
// do deep copy of p
:::
}
So the default copy constructor is called first and then the deep copy is performed.
Unfortunately this doesn't seem to work.
Is there any better way to do this?
One restriction - I can't use shared/smart pointers.
Sbi's suggestions make a lot of sense. I think I'll go with creating wrapper classes for handling the resource. I don't want to user shared_ptr since boost libraries may not be available on all platforms (at least not in standard distributions, OpenSolaris is an example).
I still think it would have been great if you could somehow make the compiler to create the default constructor/assignment operators for you and you could just add your functionality on top of it. The manually created copy constructor/assignment operator functions I think will be a hassle to create and a nightmare to maintain. So my personal rule of thumb would be to avoid custom copy constructors/assignment operators at all cost.
Thanks everybody for their responses and helpful information and sorry about typos in my question. I was typing it from my phone.
As a rule of thumb: If you have to manually manage resources, wrap each into its own object.
Put that char* into its own object with a proper copy constructor and let the compiler do the copy constructor for A. Note that this also deals with assignment and destruction, which you haven't mentioned in your question, but need to be dealt with nevertheless.
The standard library has several types to pick from for that, among them std::string and std::vector<char>.
Replace char* with std::string.
Always use RAII objects to manage unmanages resources such as raw pointers, and use exactly one RAII object for each resource. Avoid raw pointers in general. In this case, using std::string is the best solution.
If that's not possible for some reason, factor the easy to copy parts out into a base class or a member object.
You could separate your copyable members into a POD-struct and mantain your members requiring a managed copy separately.
As your data members are private this can be invisible to clients of your class.
E.g.
class A {
char *p;
struct POData {
int a, b, c, d;
// other copyable members
} data;
public:
A(const &A);
};
A(const A& a)
: data( a.data )
{
p = DuplicateString( a.p );
// other managed copies...
// careful exception safe implementation, etc.
}
You really should use smart pointers here.
This would avoid rewriting both the copy constructor and the affectation operator (operator=).
Both of these are error prone.
A common mistake with the operator= is implementing it that way:
SomeClass& operator=(const SomeClass& b)
{
delete this->pointer;
this->pointer = new char(*b.pointer); // What if &b == this or if new throws ?
return *this;
}
Which fails when one does:
SomeClass a;
a = a; // This will crash :)
Smart pointers already handle those cases and are obviously less error prone.
Moreover, Smart pointers, like boost::shared_ptr can even handle a custom deallocation function (by default it uses delete). In practice, I rarely faced a situation where using a smart pointer instead of a raw pointer was unpractical.
Just a quick note: boost smart pointer class, are header-only designed (based on templates) so they don't require additional dependencies. (Sometimes, it matters) You can just include them and everything should be fine.
The question is, do you really need a pointer with deep-copy semantics in your class? In my experience, the answer almost always is no. Maybe you could explain your scenario, so we may show you alternative solutions.
That said, this article describes an implementation of a smart-pointer with deep-copy semantics.
While I agree with others saying that you should wrap the pointer in its own class for RAII and let the compiler synthesise the copy contructor, destructor and assignment operator there is a way around your problem: declare (and define) private static function which will do whatever is needed and common for different constructors and call it from there.
Unless your class has one function, which is managing a resource, you should never manage any resources directly. Always use a smart pointer or custom management class of some description. Typically, it's best to leave the implicit copy constructor, if you can. This approach also allows easy maintenance of the destructor and assignment operators.
So the default copy constructor is called first and then the deep copy is performed.
Unfortunately this doesn't seem to work.
Is there any better way to do this? One restriction - I can't use shared/smart pointers.
If I understand correctly, your question, you could consider using an initialization function:
class A
{
int i, j;
char* p;
void Copy(int ii, int jj, char* pp); // assign the values to memebers of A
public:
A(int i, int j, char* p);
A(const A& a);
};
A::A(int i, int j, char* p)
{
Copy(i, j, p);
}
A::A(const A& a)
{
Copy(a.i, a.j, a.p);
}
That said, you really should consider using RAII ( there's a reason people keep recommending it :) ) for your extra resources.
If I can't use RAII, I still prefer creating the copy constructor and using initializer lists, for every member (actually, I prefer doing so even when using RAII):
A::A(int ii, int lj, char* pp)
: i(ii)
, j(jj)
, p( function_that_creates_deep_copy(pp) )
{
}
A::A(const A& a)
: i(a.i)
, j(a.j)
, p( function_that_creates_deep_copy(a.p) )
{
}
This has the advantage of "explicitness" and is easy to debug (you can step in and see what it does for each initialization).