My current implementation uses lots of copy constructors with this syntax
MyClass::Myclass(Myclass* my_class)
Is it really (functionnaly) different from
MyClass::MyClass(const MyClass& my_class)
and why?
I was adviced that first solution was not a true copy constructor. However, making the change implies quite a lot of refactoring.
Thanks!!!
It's different in the sense that the first isn't a copy constructor, but a conversion constructor. It converts from a MyClass* to a MyClass.
By definition, a copy-constructor has one of the following signatures:
MyClass(MyClass& my_class)
MyClass(const MyClass& my_class)
//....
//combination of cv-qualifiers and other arguments that have default values
12.8. Copying class objects
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 (8.3.6).113) [ Example: X::X(const
X&) and X::X(X&,int=1) are copy constructors.
EDIT: you seem to be confusing the two.
Say you have:
struct A
{
A();
A(A* other);
A(const A& other);
};
A a; //uses default constructor
A b(a); //uses copy constructor
A c(&a); //uses conversion constructor
They serve different purposes alltogether.
The first version is not a copy constructor. Simple as that. It's just another constructor.
A copy constructor for a class X must have signature (X &, ...) or (X const &, ...) or (X volatile &, ...) or (X const volatile &, ...), where all arguments but the first have default values if they are present (and it must not be a template).
That said, you should think very carefully about why you're violating the Rule of Zero: Most well-designed classes shouldn't have any user-defined copy-constructor, copy-assignment operator or destructor at all, and instead rely on well-designed members. The fact that your current constructor takes a pointer makes me wonder if your code behaves correctly for something like MyClass x = y; — worth checking.
Certain language constructs call for a copy constructor:
passing by value
returning by value
copy-style initialization (although the copy is often elided in that case)
If the language calls for a copy, and you have provided a copy constructor, then it can be used (assuming the cv-qualifications are OK, of course).
Since you have not provided a copy constructor, you will get the compiler-generated copy constructor instead. This works by copying each data member, even if that's not the right thing to do for your class. For example if your not-a-copy-constructor explicitly does any deep copies or allocates resources, then you need to suppress the compiler-generated copy.
If the compiler-generated copy works for your class, then your not-a-copy-constructor is mostly harmless. I don't think it's a particularly good idea, though:
void some_function(const MyClass &foo);
MyClass *ptr = new MyClass();
const MyClass *ptr2 = ptr;
some_function(ptr); // compiles, but copies *ptr and uses the copy
MyClass bar(ptr2); // doesn't compile -- requires pointer-to-non-const
Even assuming that the compiler-generated copy is no good for your class, making the necessary change need not require a lot of refactoring. Suppose that your not-a-constructor doesn't actually modify the object pointed to by its argument, so after fixing the signature you have:
MyClass::MyClass(const MyClass* my_class) {
// maybe treat null pointer specially
// do stuff here
}
You need:
MyClass::MyClass(const MyClass& my_class) {
do_stuff(my_class);
}
MyClass::MyClass(const MyClass* my_class) {
// maybe treat null pointer specially
do_stuff(*my_class);
}
MyClass::do_stuff(const MyClass& my_class) {
// do stuff here
}
You also need to copy any initializer list from the old constructor to the new one, and modify it for the fact that my_class isn't a pointer in the new one.
Removing the old constructor might require a lot of refactoring, since you have to edit any code that uses it. You don't have to remove the old constructor in order to fix any problems with the default copy constructor, though.
The first example is not a copy constructor. This means that when you provide it, the compiler still provides you with a default copy constructor with signature equivalent to
MyClass(const MyClass& my_class);
If you are doing something special with your constructor, and the compiler provided copy constructor does not follow that logic, you should either implement a copy constructor or find a way to disable it.
Why would I want to use a copy constructor instead of a conversion constructor?
It can be problematic if you give MyClass objects to some code that expect your copy-constructor to be valid.
This is the case for STL containers. For instance, if you use a std::vector<MyClass>, you must be aware that vectors are allowed to move elements around for reallocation using their copy constructors.
The default constructor provided by the compiler will perform a shallow copy, calling copy constructors of every attributes, making simple copies for base type like pointers. If you want some form of deep copy you will have to properly rewrite the copy constructor of MyClass
Related
Environment: VS2015 Update 3, 64 bit (debug|release) compile
In the code below, if I uncomment the Maybe(X&) = delete line, I get the warning mentioned in the code below and in the title of the question.
Now, I am aware, that there are certain rules in C++(11?), which might render
the explicit deletion of that constructor obsolete. Only, even after searching
the web for a while, I could not find a definite rule, which would confirm, that
if I only delete Maybe(const X&) = delete, the compiler will not auto generate the other copy constructor.
So my question is first and foremost:
Can anyone point me to spot in the C++ specification, which clearly defines the
rules for auto generation of copy constructors? Alternatively, some less official
easy to remember rule of thumb on how to be certain of what will happen would also be welcome.
template <class X>
class Maybe
{
X *m_just;
public:
explicit Maybe(const X& x)
: m_just(new X(x))
{}
Maybe()
: m_just(nullptr)
{}
Maybe(const Maybe<X>&& other)
: m_just(other.m_just)
{
other.m_just = nullptr;
}
Maybe(const Maybe<X>&) = delete;
// If line below is uncommented, this produces the warning:
// warning C4521: 'Maybe<Int32>': multiple copy constructors specified
// Maybe(Maybe<X>&) = delete;
~Maybe()
{
delete m_just;
m_just = nullptr;
}
// ... more members and code which are not related to question
// ...
};
Please do not comment on the whole idea of that class. It is just private tinkering in my private lab... ;)
The compiler will only generate one of Maybe(Maybe<X>&) and Maybe(const Maybe<X>&).
The conditions for the choice are listed in section 12.8, paragraph 8:
The implicitly-declared copy constructor for a class X will have the
form X::X(const X&) if
each direct or virtual base class B of X has a copy constructor whose first parameter is of type const B& or const volatile B&, and
for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy constructor whose
first parameter is of type const M& or const volatile M&
Otherwise, the implicitly-declared copy constructor will have the form
X::X(X&)
Or more informally, the parameter will be const if and only if everything that needs to be copied can be "const-copied".
Deleting one will not cause the other to be generated.
Since you have no base class and your only member is a pointer, the generated constructor will be of the const variety and you can leave out the line causing an error.
My C++ is a little bit rusty so this might be wrong, but I don't think you should even have a non-const copy constructor (except for the move constructor naturally).
If a = b changes b you're going to surprise some people. Perhaps it's legitimate for the copy constructor to change the source in a way that's not externally visible, but in that case I think you're better off using const_cast inside the const copy constructor.
The error I don't think is about delete, it's about defining multiple copy constructors, which isn't allowed. I suspect even allowing the non-const copy constructor is a bit of a wart in the language.
other.m_just = nullptr;
This line should not compile. Something must be wrong with your compiler, or your code example doesn't exactly reflect what you're compiling.
Anyway, the move constructor should take a non-const rvalue reference.
The commented line is simply not necessary. Just leave it out. If you define the copy constructor (even as deleted), no other form of the copy constructor is defined by the compiler, ever, so if you leave the line out, there simply is no constructor that takes a non-const reference to Self, meaning that overload resolution will just pick the const reference copy constructor, which is deleted anyway.
I'm trying to initialize one object into other object using copy constructor. I'm puzzled that if I comment out copy constructor it initializes fine but with following code it does not.
class TDateTime : public TData {
public:
TDateTime() : TData(EDataStateInvalid) {}
TDateTime(const tm& aTm){};
TDateTime(int aTm_sec, int aTm_min, int aTm_hour,
int aTm_mday, int aTm_mon, int aTm_year, int aTm_wday,int aTm_isdst){
value.tm_sec=aTm_sec;
value.tm_min=aTm_min;
value.tm_hour=aTm_hour;
value.tm_mday=aTm_mday;
value.tm_mon=aTm_mon;
value.tm_year=aTm_year;
value.tm_wday=aTm_wday;
value.tm_isdst=aTm_isdst;
};
virtual ~TDateTime() {cout<<"Destroying TDateTime ";};
//! Copy constructor
TDateTime(const TDateTime& aInstance){};
//! Copies an instance
virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
private:
tm value;
};
main.cpp
tm=createDateTime(x);
TDateTime aDateTimeFrom(tm.tm_sec,tm.tm_min,tm.tm_hour,tm.tm_mday,tm.tm_mon,tm.tm_year,tm. tm_wday,0);
TDateTime aDateTimeTo(aDateTimeFrom);
if I comment out the copy constructor it copies fine. If I remove {} then compiler complains about undefined symbol.
Can you suggest what is wrong here?
Based on answer about empty copy constructor does nothing, I comment it out and copy is perfect but I have another problem. If I do
TDateTime aDateTime;
aDateTime=aDateTimeFrom;
aDateTime has all junk values. Any pointers on this?
//! Copy constructor
TDateTime(const TDateTime& aInstance){};
Your copy constructor does nothing. There is no magic involved with user-written copy constructors; if you don't make them do anything, then they will not do anything.
More precisely, a new instance is created, but its members are left uninitialised or are default-initialised.
While we're at it...
//! Copies an instance
virtual const TDateTime& operator=(const TDateTime& aInstance){return *this;};
Same problem here. Your copy-assignment operator does not do anything.
By convention, it should also not return a const reference but a non-const one.
It may be worth the mention that your intution seems to be correct, as your goal should indeed be to create classes which don't require any self-written copy constructors or copy-assignment operators because all members know how to correctly copy or copy-assign themselves (like std::string or std::vector or std::shared_ptr). But in that case, rather than defining the member functions with empty implementations, you just don't declare them at all in your code, such that the compiler can handle everything automatically.
And finally, one other thing: A good rule of thumb for C++ classes is that they should either have virtual functions and disable copying (sometimes called "identity classes") or have no virtual functions and allow copying (sometimes called "value classes"). Something like a virtual assignment operator often indicates an overly complicated, hard-to-use and error-prone class design.
A compiler generates a copy constructor which performs member-wise copy if the user hasn't declared a copy constructor. If the user does declare a copy-constructor, then the copy constructor does what the user has told it to, in your case - exactly nothing.
TDateTime(const TDateTime& aInstance){ /* empty body*/};
Your define a copy constructor which does not do anything.
In your case you don't really need a copy constructor and/or copy assignment operator, the compiler generated versions would be enough (it would be wise to make sure/recheck that tm class can handle the copying).
There is a rule of three, which states that one needs copy constructor and copy assignment operator if one defines a destructor. But it is only a rule of thumb and not an actual necessity. In your case there is no memory management involved and you use the destructor only for logging.
So do not declare a copy constructor at all (your assign operator has the same flaw by the way - it does not copy anything) and let the compiler do the work.
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.
I have never written copy constructor, so in order to avoid pain i wanted to know if what i have coded is legit. It compiles but i am not sure that it works as a copy constructor should.
Also do i have to use const in the copy constructor or i can simply drop it. (What i dont like about const is that the compiler cries if i use some non const functions).
//EditNode.h
class EditNode
{
explicit EditNode(QString elementName);
EditNode(const EditNode &src);
}
//EditNodeContainer.h
class EditNodeContainer : public EditNode
{
explicit EditNodeContainer(QString elementName);
EditNodeContainer(const EditNodeContainer &src);
}
//EditNodeContainer.cpp
EditNodeContainer::EditNodeContainer(QString elementName):EditNode(elementName)
{
}
//This seems to compile but not sure if it works
EditNodeContainer::EditNodeContainer(const EditNodeContainer &src):EditNode(src)
{
}
//the idea whould be to do something like this
EditNodeContainer *container1 = new EditNodeContainer("c1");
EditNodeContainer *copyContainer = new EditNodeContainer(container1);
A copy constructor is a constructor that has one of the following signatures:
class A
{
A(A& other);
//or
A(const A& other);
//or
A(volatile A& other);
//or
A(const volatile A& other);
//or any of the above + other parameters that have default arguments
//example:
A(const A& other, int x = 0) //this is also a copy constructor
};
The above is specified in 12.8.2 of the standard - C++03.
so you are implementing correctly a copy constructor.
The reason it should receive a const parameter is that you're not changing the object you're copying from. If you call non-const functions on it, you're doing something wrong.
Also, in your snippet
EditNodeContainer *container1 = new EditNodeContainer("c1");
EditNodeContainer *copyContainer = new EditNodeContainer(container1);
you're not calling a copy constructor, because you're passing an EditNodeContainer* as parameter, not a EditNodeContainer.
You're missing one * symbol. Copy constructor expects reference to object, but is given pointer to object. Just replace container1 with *container1 as parameter of copy constructor.
The parameter of a copy constructor can be an lvalue reference to non-const or an lvalue reference to const, but in practice it is always a reference to const (the deprecated auto_ptr is an exception).
You should not write a copy constructor unless you have to and you fully understand the consequences. If you are consequent in using RAII classes everywhere, you rarely need a custom copy constructor (unless you are writing a RAII class).
Also, please avoid raw pointers and new wherever possible.
If the operator= is properly defined, is it OK to use the following as copy constructor?
MyClass::MyClass(MyClass const &_copy)
{
*this = _copy;
}
If all members of MyClass have a default constructor, yes.
Note that usually it is the other way around:
class MyClass
{
public:
MyClass(MyClass const&); // Implemented
void swap(MyClass&) throw(); // Implemented
MyClass& operator=(MyClass rhs) { rhs.swap(*this); return *this; }
};
We pass by value in operator= so that the copy constructor gets called. Note that everything is exception safe, since swap is guaranteed not to throw (you have to ensure this in your implementation).
EDIT, as requested, about the call-by-value stuff: The operator= could be written as
MyClass& MyClass::operator=(MyClass const& rhs)
{
MyClass tmp(rhs);
tmp.swap(*this);
return *this;
}
C++ students are usually told to pass class instances by reference because the copy constructor gets called if they are passed by value. In our case, we have to copy rhs anyway, so passing by value is fine.
Thus, the operator= (first version, call by value) reads:
Make a copy of rhs (via the copy constructor, automatically called)
Swap its contents with *this
Return *this and let rhs (which contains the old value) be destroyed at method exit.
Now, we have an extra bonus with this call-by-value. If the object being passed to operator= (or any function which gets its arguments by value) is a temporary object, the compiler can (and usually does) make no copy at all. This is called copy elision.
Therefore, if rhs is temporary, no copy is made. We are left with:
Swap this and rhs contents
Destroy rhs
So passing by value is in this case more efficient than passing by reference.
It is more advisable to implement operator= in terms of an exception safe copy constructor. See Example 4. in this from Herb Sutter for an explanation of the technique and why it's a good idea.
http://www.gotw.ca/gotw/059.htm
This implementation implies that the default constructors for all the data members (and base classes) are available and accessible from MyClass, because they will be called first, before making the assignment. Even in this case, having this extra call for the constructors might be expensive (depending on the content of the class).
I would still stick to separate implementation of the copy constructor through initialization list, even if it means writing more code.
Another thing: This implementation might have side effects (e.g. if you have dynamically allocated members).
While the end result is the same, the members are first default initialized, only copied after that.
With 'expensive' members, you better copy-construct with an initializer list.
struct C {
ExpensiveType member;
C( const C& other ): member(other.member) {}
};
};
I would say this is not okay if MyClass allocates memory or is mutable.
yes.
personally, if your class doesn't have pointers though I'd not overload the equal operator or write the copy constructor and let the compiler do it for you; it will implement a shallow copy and you'll know for sure that all member data is copied, whereas if you overload the = op; and then add a data member and then forget to update the overload you'll have a problem.
#Alexandre - I am not sure about passing by value in assignment operator. What is the advantage you will get by calling copy constructor there? Is this going to fasten the assignment operator?
P.S. I don't know how to write comments. Or may be I am not allowed to write comments.
It is technically OK, if you have a working assignment operator (copy operator).
However, you should prefer copy-and-swap because:
Exception safety is easier with copy-swap
Most logical separation of concerns:
The copy-ctor is about allocating the resources it needs (to copy the other stuff).
The swap function is (mostly) only about exchanging internal "handles" and doesn't need to do resource (de)allocation
The destructor is about resource deallocation
Copy-and-swap naturally combines these three function in the assignment/copy operator