How to handle required default constructor - c++

In writing a copy constructor for one of my classes ( which holds a few objects of other UDTs ), I am required to create a default constructor for those UDTs, even though they were never really meant to have one.
Is it fine to just implement a blank default constructor and be done with it? The only time the default constructor is invoked is during this copying, when the object is created and then the values of the corresponding object are copied to it. Thus, whatever values are assigned to the object in the default constructor will never actually be used.
The problem I see is that some member variables aren't initialized in a blank default constructor. Should I just write one that gives dummy values instead? Any other recommended ways to handle this?
Edit: I understand that a copy constructor doesn't NEED a default constructor if I were to define copy constructors for the other classes, but I didn't, so it does need it.

If you use an initializer list in the copy constructor, you don't need a default constructor:
#include <iostream>
using namespace std;
class Foo {
Foo(); /* no default constructor */
public:
Foo(int i) { cout << "Foo constructor (int)" << endl; }
Foo(const Foo& f) { cout << "Foo constructor (copy)" << endl; }
};
class Bar {
Foo f;
public:
Bar() : f(1) { cout << "Bar constructor (default)" << endl; }
Bar(const Bar& b) : f(b.f) { cout << "Bar constructor (copy)" << endl; }
};
int main(void) {
Bar b;
Bar b_=b;
return 0;
}
Results in:
Foo constructor (int)
Bar constructor (default)
Foo constructor (copy)
Bar constructor (copy)

Are you actually sure you need a copy constructor? It's unusual (but not impossible) to have a class where the default constructor would be OK, but you need a custom copy constructor. Perhaps you could post the code for your class?

It sounds to me like you need to define copy c'tors for the other classes, as you are creating objects of them by copying other objects.

You say:
when the object is created and then
the values of the corresponding object
are copied to it.
But ask yourself - how do the values of that "corresponding object" get there in the first place. I.e. how was the corresponding object created?
This previous SO discussion may help clarify matters for you.

This doesn't sound like the best way to implement a copy constructor. If the contained types provide copy constructors themselves - use those. There might be a reason a type does not provide a default constructor after all.

I would first ask why copying those UDTs involves the default constructor, rather than the more appropriate copy constructor. I would also ask what it means for an object to be in the default initialized state — if it does mean something, then by all means implement it.
If you have no reasonable meaning for a default initialization, and you absolutely have to define the object using a default constructor, I suppose implementing a default constructor could be afforded.
However, not all objects can get a default constructor, so fixing the source of the problem is still a good idea.

You can prevent the default constructor by requiring the other object to have copy constructors also (Or use special constructor which pass in all information needed to construct the objects. Generally having default constructor which don't initialize all member variables is a very bad idea. At a minimum make sure the default constructors of the other class initializes all members.

If you don't want the compiler to generate a copy constructor or don't want a copy constructor at all, then declare a private copy constructor but don't provide any definition (code) for it. The compiler will see the declarations and not generate one. Also do this with the assignment operator.
I do this with my singleton classes.

If your class isnt meant to be defaultly constructed, don't create a default constructor.
If it is, then I'm sure you can figure out a sensible initialization, so that's what you should be using.

Remember a thumb rule that as far as something is not part of specification , compiler won't do it for you.
If your class contain user defined type and when you create object of it , then compiler has to call default constuctor for each object.
But to initialize data members of object is not complier's task, but you are suppose to do it.
For the case you have mentioned , you need your own custom copy constructor and assignment operator.

The question, the way you stated it, appears to make no sense. Copy-constructor does not need the default constructor, as you seem to believe. Copy-constructor is a completely independent full-fledged constructor that construct an object completely by itself.
If you construct your objects with copy-constructor, then you don't need a default one. If you construct your objects with default constructor, then you can't use the copy-constructor on them. It is not possible to "apply" two different constructors to the same object.
If you construct your objects in both ways, then they become two completely independent constructors, each having its own independent purpose. In this case the question you should be asking yourself is how you want your objects to be defualt-constructed. Only you know that.
Again, you need to clarify your question. I would suspect (from your description) that maybe what you are trying to implement is not copy-constructor, but a copy-assignment operator. But that's just a wild guess.

Related

What are the benefits of using copy constructor?

I am new to object oriented programming, and this may be a silly question, but I don't understand why is using class A code better to use than class B if you want to create copy of one object.
class A {
int num;
public:
A(const A &ref) : num(ref.num) {};
};
class B {
int num;
public:
B(B *ptToClass) : num(ptToClass->num) {};
};
If I got this right, copy constructor is used in class A.
If you don't declare a copy constructor for your class, the compiler will declare one for you anyway. Classes have to have copy constructors. They're baked into the language and have special status. The language doesn't work without them.
Possibly the best example is that copy constructors are needed when passing by value. The compiler is going to implicitly call the copy constructor when you pass by value. It's not going to call the constructor B::B(B*).
So if you want your class to be copyable, you should define the copying logic in the copy constructor. It's just easier.
Class A is flexible and safe: you create a copy from any A object you have, even if it's a temporary one.
Class B is less safe as you could invoke the constructor with a nullptr. It's less flexible because you can only use ypur constructor to copy an object from which you can get the address and which is not const.
B b1(...);
const B b2(...);
B fb(); // function returning a B
B b3(&b1);
B b4(&b2); // error b2 is const
B b5(&fb()); // error you can't take adress of a temporary
The thing is that if a constructor is considered to be a copy constructor by the compiler, it is used in special ways. For instance, if you have a function that takes a parameter of your type A by copy, like this:
void function(A obj) {
// Do something with A
// ...
}
And then you call that function:
int main() {
A a_obj;
function(a_obj);
}
the object obj received by function will be created by the copy constructor you provided. So, it is a nice thing to provide copy constructor for your classes that are meant to be copied, so that them fits more nicely with the languages features and libraries.
There is no problem in creating a constructor of the kind in your class B, if that fit your needs in your application, but that will not be understood by the compiler as a copy constructor, and won't be used when the compiler or libraries needs to copy your objects.
It is forbidden by standard to use pointers in copy constructors:
C++ draft standard n3376 - section 12.8.2:
A non-template constructor for class X is a copy constructor if its
first parameter is of type X&, const X&, volatile X& or const volatile
X&, and either there are no other parameters or else all other
parameters have default arguments
Why is the argument of the copy constructor a reference rather than a pointer?
I think a more appropriate question to ask is: when to provide a user-defined copy constructor over the default one provided by the compiler?
As we know, the compiler provides a copy constructor (the default one) which does a memberwise copy.
This memberwise copy is not bad as long as the class is a simple concrete type (that behaves for the most part like a built-in type). But for complex concrete types or classes with hierarchies, memberwise copy is not a good idea, and the programmer is highly advised to provide his own implementation of the copy constructor (that is, provide user-defined copy constructor).
As a thumb rule, it is a good idea to provide user-defined copy constructor in the class.

Deleted vs empty copy constructor

Examples of empty and deleted copy constructors:
class A
{
public:
// empty copy constructor
A(const A &) {}
}
class B
{
public:
// deleted copy constructor
A(const A&) = delete;
}
Are they doing the same in practice (disables copying for object)? Why delete is better than {}?
Are they doing the same in practice (disables copying for object)?
No. Attempting to call a deleted function results in a compile-time error. An empty copy constructor can be called just fine, it just default-initializes the class members instead of doing any copying.
Why delete is better than {}?
Because you're highly unlikely to actually want the weird "copy" semantics an empty copy constructor would provide.
One reason is syntactic sugar -- no longer need to declare the copy constructor without any implementation. The other: you cannot use deleted copy constructor as long as compiler is prohibited from creating one and thus first you need to derive new class from that parent and provide the copy constructor. It is useful to force the class user to create own implementation of it including copy constructor for specific library class. Before C++ 11 we only had pure virtual functions with similar intent and the constructor cannot be virtual by definition.
The default or existing empty copy constructor does not prevent an incorrect use of the class. Sometimes it is worth to enforce the policy with the language feature like that.
Empty Copy constructor is used for default initializing the member of class.
While delete is use for prevent the use of constructor.

Why is the compiler bugging me on this one?

(using Visual C++ 2010, compiling in debug with optimizations turned off)
I have the following very simple class:
class exampleClass
{
public:
exampleClass()
{
cout << "in the default ctor" << endl;
}
private:
exampleClass (const exampleClass& e)
{
cout << "in the copy ctor" << endl;
}
};
When I try to compile it with the following main:
#include <iostream>
using namespace std;
int main()
{
exampleClass e1=exampleClass();
return 0;
}
I get the compilation error:
'exampleClass::exampleClass' : cannot access private
member declared in class 'exampleClass'
When I remove the access modifier "private" from the copy ctor, the program compiles and prints only:
in the default ctor
Why is this happening? If the compiler will not invoke the copy ctor anyway, why is it bugging me?
Since some people missed the first line (at least before some edits) i will repeat it:
I compiled in debug with optimizations turned off.
This type of initialization is called copy-initialization. I believe the following clause from the C++11 standard applies here (paragraph 8.5.16, page 204):
If the initialization is direct-initialization, or if it is
copy-initialization where the cv-unqualified version of the source
type is the same class as, or a derived class of, the class of the
destination, constructors are considered. The applicable constructors
are enumerated (13.3.1.3), and the best one is chosen through overload
resolution (13.3). The constructor so selected is called to initialize
the object, with the initializer expression or expression-list as its
argument(s). If no constructor applies, or the overload resolution is
ambiguous, the initialization is ill-formed.
In this case, the best applicable constructor is the copy ctor, which is private, hence the error message.
To further answer your question, when the copy ctor is private, your program is simply not allowed to pass the complier check because of the rules imposed by the standard. When you make the copy ctor public, the program becomes valid, but the call to the copy ctor is optimized away.
EDIT:
Okay, to elaborate on previous paragraph.You're dealing here with the so-called copy elision. While the copy elision is possible in this case, the standard requires you to provide an accessible copy ctor for your class.
exampleClass e1=exampleClass();
This will first create a temporary exampleClass using the default constructor and then copy that into e1 using the copy constructor. This will invoke the private copy constructor and thus give you the error. The corrent way to instantiate an instance of a class with the default constructor is this:
exampleClass e1;
The compiler is required to bug you there. While the copy can be elided, the standard requires that the copy constructor is accessible for that type of construction. Of course, you can simplify the code and avoid the copy construction altogether:
exampleClass e1; // Will call exampleClass::exampleClass()
exampleClass e1=exampleClass();
is the same as:
exampleClass e1(exampleClass());
i.e it invokes the (private) copy constructor.
This is because at compile time, the compiler checks if the function the user is trying to access is really accessible. So when you use exampleClass e1=exampleClass();, it first checks if the copy-constructor is accessible. It spits out an error because the copy-constructor is not private. Remember that at this point the compiler hasn't gone onto the optimization stage where it does the clever stuff as to skip the copy-constructor.
When you make the copy-constructor public, the compiler successfully goes through the stage of parsing the code and making sure that everything is accessible and is in order (there's actually more than that going on) and then at the optimization stage, which usually is on in 'Release' mode it does the clever stuff and by-passes the use of copy-constructor. However if you tried the same code in 'Debug' mode you'd see that the copy-constructor does get called.
Everyone explains how you should instantiate an object and #Grigory Javadyan makes a good point on copy elision. It looks like, MSVC does this optimization (so called return value optimization) even in debug mode.
exampleClass e1=exampleClass();
is the same as
exampleClass giveExample()
{
return exampleClass();
}
exampleClass e1 = giveExample();
You will see that copy ctor will not be called.
But here :
exampleClass giveExample()
{
exampleClass example;
return example;
}
exampleClass e1 = giveExample();
you will see another output line :
in the copy ctor
Because you are forcing the compiler to first generate an object and then return it.
Here, here and here some questions I can find, similar to yours.
PS. Link#2 is from another Q&A site. I hope this is not a problem.
That's not how you do instantiate an object in C++. If you want it allocated on the stack, you write:
exampleClass e1;
and you're done, sincee exampleClass' constructor accepts no parameters.
Otherwise, if you want it allocated on the heap, you write:
exampleClass e1 = new exampleClass();
The way you wrote it actually creates a temporary object and invokates the copy constructor on that temporary object to create e1. Problem is that your copy-ctor is private, so the compiler's error message.
when you write
exampleClass e1 = exampleClass()
it is the same as writing
exampleClass e1( exampleClass() );
which invokes the copy ctor.
Its because the copy constructor is private..
your code is
creating a temporary exampleClass and invoking the default constructor exampleClass()
attempting to assign the resulting temporary object to e1 using the private copy constructor

how to write a constructor

is that correct to write a constructor like this?
class A
{
A(const A& a)
{
....
}
};
if yes, then is it correct to invoke it like this:
A* other;
...
A* instance = new A(*(other));
if not, what do you suggest?
Thanks
Almost correct. When declaring the constructor in the class, simply write A, not A::A; you would use A::A when giving a definition for the constructor outside of the class declaration. Otherwise, yes.
Also, as James points out, unless you are copying from an object that you are accessing via a pointer, you don't need to do any dereferencing (if it is a value or a reference). One typically does not use pointers unless it is necessary to do so. On that principle, you would have something like:
A x; // Invoke default constructor
// ...
// do some thing that modify x's state
// ...
A cpy(x); // Invokes copy constructor
// cpy now is a copy of x.
Note, though, that the first statement A x invokes the default constructor. C++ will provide a default implementation of that constructor, but it might not be what you want and even if it is what you want, it is better style, IMHO, to give one explicitly to let other programmers know that you've thought about it.
Edit
C++ will automatically provide an implementation of the default constructor, but only if you don't provide any user-defined constructors -- once you provide a constructor of your own, the compiler won't automatically generate the default constructor. Truth be told, I forgot about this as I've been in the habit of giving all constructor definitions myself, even when they aren't strictly necessary. In C++0x, it will be possible to use = default, which will provide the simplicity of using the compiler-generated constructor while at the same time making the intention to use it clear to other developers.
No, you are writing a copy constructor. It will not act as you expect (according to the examples provided).
class A{
A(arguments){ ...}
}
I would suggest reading a C++ book, differences between a constructor and a copy constructor are well explained.
When is it used ? When an instance is copied. For example, by returning /passing an instance by value
void foo (A a){
//copy constructor will be called to create a
}
A bar(){
return a; //Copy constructor will be called
}

Copy constructors - c++

Can I write a copy constructor by just passing in a pointer instead of the const reference? (Would it be ok if I make sure that I am not going to change any values though?)
Like so:
SampleClass::SampleClass(SampleClass* p)
{
//do the necessary copy functionality
}
instead of:
SampleClass::SampleClass(const SampleClass& copyObj)
{
//do the necessary copy
}
Thanks in advance.
Thanks everyone. So, if I write a constructor that takes in a pointer( and thought that's my copy constructor), the compiler would still supply with the default copy constructor in which case my constructor( which i thought was my copy constructor) would not be called and the default copy constructor would be called. Got it.
Yes, you can write a constructor that takes a pointer to the object. However, it cannot be called a copy constructor. The very definition of a copy constructor requires you to pass an object of the same class. If you are passing anything else, yes, it's a constructor alright, but not a copy constructor.
You can write a constructor that takes a pointer as an argument.
But the copy constructor is the name we give a specific constructor.
A constructor that takes a reference (preferably const but not required) of the same class as an argument is just named the copy constructor because this is what it effectively does.
Besides the fact that it would not be a copy constructor and the compiler will generate the copy constructor unless you explicitly disable it, there is nothing to gain and much to loose. What is the correct semantics for a constructor out of a null pointer? What does this add to the user of your class? (Hint: nothing, if she wants to construct out of a heap object she can just dereference the pointer and use the regular copy constructor).
No. Copy constructors must take a reference, not pointer, if it's to be useful for passing-by-value, etc.
By definition, the copy ctor uses a const reference. While there is nothing stopping you from writing a ctor that takes a pointer, it raises some problems not present when using a reference - e.g., what should/can happen if a null pointer is passed in?
A copy constructor needs a reference because a value parameter would require making a copy, which would invoke the copy constructor, which would make a copy of its parameter, which would invoke the copy constructor, which ...
You can write a constructor like that but its not technically a copy constructor. For example the STL containers will still use the compiler generated copy constructor (the compiler generates one because you didn't write one).
The copy constructor is implicitly used in two cases:
When an instance of your class is passed by value to a function.
When an instance of your class is returned by value from a function.
As others have mentioned, you can write a constructor with the signature described (or with a const pointer), but it would not be used in either of the above cases.
You can write a perfectly valid copy constructor, and still be able to pass a reference that is NULL. You can test for NULL, but only if you do not use constructor initialization lists.
Example:
MyClass::MyClass( MyClass const& MyClassCopy )
: somevar( MyClassCopy.somevar ) // <- the init list goes here.
{
// If MyClassCopy is NULL, the initialization above is doomed!
// However we can check for NULL in the constructor body but
// the initialization list must be removed ...
if (&MyClassCopy == NULL ) throw( std::runtime_error("NULL pointer!"));
somevar = MyClassCopy.somevar;
}
// I'll now do some very dangerous programming to
// demonstrate one way that a NULL can get through ...
MyClass* P = NULL;
MyClass A( *P ); // Bang, you're dead!
As far as I know, there's no way to check for a NULL from inside the initialization list, so if you think you could end up with a situation where a NULL gets through, you have to test for it in the constructor body and do the initializing from there.
Don't forget there's a few gotchas with ::operator=() function to be aware of ...