The question: Can I define an assignment operator and not the copy constructor? For an internal class (not exposed in the API), is this still a bad design practice?
The reason I need it: As this question mentions, QObject makes its copy constructor and assignment operator private so that if a subclass tries to use either, an error is issued at compile-time.
I need to define an assignment operator however in order to copy the "value" (and not the "identity" as the Qobject documentation describes. I don't use this class's copy constructor anywhere.
The reason I don't want to write a copy constructor is that it will be duplicating code that I won't use anyway.
There's nothing stopping you. It is, however, a pretty dumb idea.
T t = GetSomeT();
versus
T t;
t = GetSomeT();
Pretty trivial to transform the first into the second, but you're just wasting my time, both dev and processor, making me do it. If it's not default-constructible, I guess that it would be harder... but I'm still not seeing the point. The copy constructor can be defined by the compiler if it's trivial, or you can even define it in terms of the assignment operator if you want DRY.
class T {
T(const T& ref) {
*this = ref;
}
};
Not having a copy constructor will also inhibit your ability to copy-and-swap, the usual idiom for implementing assignment operators.
While possible, as DeadMG says, it is rather foolish.
You don't have to call the base class's copy constructor from your own, so if you absolutely have to have value semantics, then it is still possible. But in the context of QObjects, this is still rather unorthodox. Even for your own internal classes, the principle of least surprise still needs to be kept in mind.
If absolutely necessary, I would avoid the traditional copy constructor/assignment operator, and work via member functions. The expected semantics of QObject derivatives will be maintained, but you have a way to explicitely do what you want to have done.
struct SomeType : QObject {
QSharedPointer<SomeType> Clone() const;
//or
SomeType& CopyValue(const SomeType&);
//rest of implementation
};
Related
I've read that The Rule of Three, What is The Rule of Three? is summarized as follows:
If you need to explicitly declare either the destructor, copy constructor or copy assignment
operator yourself, you probably need to explicitly declare all three of them.
My question is: In a C++ application, I have a class that manages resources (has a destructor that handles deleting pointers). I know that the application uses assignment operator all over the place, but I am absolutely certain that there is no usage in the application of a copy constructor, i.e., usage of the type Class c(..); Class d(c); so under these circumstances, am I still required to implement both an assignment operator and a copy constructor? Or will an assignment operator alone suffice? Is it possible that the assignment operator uses the copy constructor somehow?
Appreciate your thoughts.
If you know that the copy constructor won't be used, you can express that by making it private and unimplemented, thus:
class C
{
private:
C(const C&); // not implemented
};
(in C++11 you can use the new = delete syntax). That said, you should only do that if you're absolutely sure it will never be needed. Otherwise, you might be better off implementing it. It's important not to just leave it as is, as in that case the compiler will provide a default memberwise copy constructor that will do the wrong thing - it's a problem waiting to happen.
To some extent it depends on what the class is going to be used for - if you're writing a class that's part of a library, for instance, it makes much more sense to implement the copy constructor for consistency reasons. You have no idea a priori how your class is going to be used.
I am absolutely certain that there is no usage in the application of a copy constructor, i.e., usage of the type Class c(..); Class d(c)
Are you aware that the following code
Foo c;
Foo b = c;
invokes the copy constructor and NOT the assignment operator? I'd implement the copy constructor just to be safe.
In almost all cases, the compiler will generate these methods for you and you don't need to do anything. But, if implicitly generated copy constructor/assignment operator won't do what you want, and design-wise your class makes sense to be able to be copied, you should explicitly provide a copy ctor and assignment operator whether you use them both or not (as good practice).
If, design-wise, your class makes sense to be noncopyable, you can declare but not define the copy ctor/assignment op.
I've read that The Rule of Three, What is The Rule of Three? is summarized as follows:
If you need to explicitly declare either the destructor, copy constructor or copy assignment
operator yourself, you probably need to explicitly declare all three of them.
My question is: In a C++ application, I have a class that manages resources (has a destructor that handles deleting pointers). I know that the application uses assignment operator all over the place, but I am absolutely certain that there is no usage in the application of a copy constructor, i.e., usage of the type Class c(..); Class d(c); so under these circumstances, am I still required to implement both an assignment operator and a copy constructor? Or will an assignment operator alone suffice? Is it possible that the assignment operator uses the copy constructor somehow?
Appreciate your thoughts.
If you know that the copy constructor won't be used, you can express that by making it private and unimplemented, thus:
class C
{
private:
C(const C&); // not implemented
};
(in C++11 you can use the new = delete syntax). That said, you should only do that if you're absolutely sure it will never be needed. Otherwise, you might be better off implementing it. It's important not to just leave it as is, as in that case the compiler will provide a default memberwise copy constructor that will do the wrong thing - it's a problem waiting to happen.
To some extent it depends on what the class is going to be used for - if you're writing a class that's part of a library, for instance, it makes much more sense to implement the copy constructor for consistency reasons. You have no idea a priori how your class is going to be used.
I am absolutely certain that there is no usage in the application of a copy constructor, i.e., usage of the type Class c(..); Class d(c)
Are you aware that the following code
Foo c;
Foo b = c;
invokes the copy constructor and NOT the assignment operator? I'd implement the copy constructor just to be safe.
In almost all cases, the compiler will generate these methods for you and you don't need to do anything. But, if implicitly generated copy constructor/assignment operator won't do what you want, and design-wise your class makes sense to be able to be copied, you should explicitly provide a copy ctor and assignment operator whether you use them both or not (as good practice).
If, design-wise, your class makes sense to be noncopyable, you can declare but not define the copy ctor/assignment op.
I recently read, Rule of three and am wondering if I am violating it?
In my GUI application, classes like MainFrame, Interface, Circuit, Breadboard etc. (class name are indicative) have a single instance of each of them. In their constructors, I have allocated some resources (memory), which I safely release in their destructors.
So I have defined only destructor, but not copy constructor and assignment operator.
I am sure I don't need them, but I am curious if I am violating the rule, and what can/should I do to follow it?
The rule of three is about dealing with all the Big Three, but that does not necessarily mean you'll have to define them if you don't want to. Either you provide them or you forbid them. What you shouldn't do is ignore them.
So I have defined only destructor, but not copy constructor and copy operator.
Am I violating Rule of three?
Yes, you are in violation of the rule. The compiler will generate a copy constructor and copy assignment operator, and since you allocate memory in the constructor and release in the destructor, these copies will have wrong semantics: they'll copy the pointers, and you will have two classes aliasing the same memory. The assignment won't even release the old memory, and simply overwrite the pointer.
Is this a problem?
If, like you imply, you don't make copies or assign to instances of those classes, nothing will go wrong. However, it's better to be on the safe side and declare (and don't even bother defining) the copy constructor and copy assignment operator private, so you don't invoke them accidentally.
In C++11 you can use the = delete syntax instead:
T(T const&) = delete; // no copy constructor
T& operator=(T const&) = delete; // no copy assignment
It depends a lot on you application logic and how the you have documented your interface classes to the users.
Normally, a good c++ programmer must be aware of rule of three (and a half if you know the "copy and swap idiom") and 5 and a 1/2 in case of c++11 (Move semantics).
If you class manages resource and if the same class is copyable (i.e copy ctor and assigment operator not defined as private) then its very important to do deep copying by writing your own copy ctor and assignment operator.
But If you are always toying your class by passing them as REFERENCE then better define a default copy ctor and assignment operator as private so that even if you pass by valy or copy by mistake, the compiler would warn you.
You should declare (but not implement) a private copy constructor and assignment operator. Make sure you don't implement the functions. This will prevent any kind of copying of classes not supposed to be copied.
Yes, it does violate the rule of three as per that definition.
It is, however, a "rule of thumb". A general guideline. If you don't need copy construction or assignment operations, don't implement them. Others have suggested declaring them as private and defining them as empty. I'd go one step further and say don't even define them.
If you define them, then you could potentially still invoke the empty methods. Instead, leave them undefined and, if you ever try to invoke those methods, you will receive a linker error because the method definitions could not be found. Favor build-time errors over run-time errors/undesired behavior.
If you don't need it, don't follow it. The motivation behind the rule of three is that, when you need a destructor, that is usually because you need to do some dynamic deallocations.
If you do deallocations as well, you're going to need the copy constructor and assignment operators as well. Imagine you have a class that has a pointer to something:
struct Foo
{
Foo() { ptr_ = new int; }
~Foo() { delete ptr_; }
int* ptr_;
};
Because you don't define a copy constructor and an assignment operator, whenever you make a copy of a Foo, both the original and the copy will use a pointer to the same int; when either the original or the copy gets destroyed, the pointer is freed, leaving the other with unusable data.
Foo(cont Foo& other) {
other.ptr_ = new int(*ptr_);
}
// Same for operator=
If you don't do any dynamic allocations in your constructor/ destructor, there's a good chance you don't actually need a copy constructor or an assignment operator (but not necessarily).
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why copy constructor and assignment operator are disallowed?
I'm learning C++ from a solid C background, and in the eagerness to avoid the errors of previous C++ that I gleaned from reddit and hacker news, I've been using the Google C++ style guide and LLVM's source code as references for my own code. One thing that sticks out is both the projects' use of the following code. The following is taken from LLVM's include/Support/MemoryBuffer.h:
MemoryBuffer(const MemoryBuffer &); // DO NOT IMPLEMENT
MemoryBuffer &operator=(const MemoryBuffer &); // DO NOT IMPLEMENT
Google echoes this usage. Clearly, it's a good thing to disable these "copy constructors".
So my question is: why are these things so scary, and (if they are not guarded against) what does their use look like and what effect does it cause in code?
When an object has to manage its own resources, such as memory or a system handle, then the default copy constructor and assignment operator are no longer appropriate. That means you have to override them.
However, sometimes it doesn't make any sense to copy such an object. Or, said differently, some objects are not meant to be copied. Sometimes it's not even possible to write such a constructor or assignment operator. In that case, it's best to disable copy and assignment to make sure they're not copied by accident.
The standard's iostream are a good example.
All in all, it's a, say, special case. Definitely not something you would encounter often.
There is nothing scary about copy-constructors and they should not be viewed as such.
However, that said, there are times where copying an object simply doesn't make sense. In the example you provided, a memory buffer is a good example of something that makes no sense to copy. It has perhaps been used to store the data of allocated objects. What does a copy provide? A duplicate of the raw data of all those objects and not much else (the objects can't use it to de-allocate with, for example).
So, once we have decided that it makes no sense to copy our class, it also makes sense that we should prevent the programmer from doing it. The compiler will be sneaky and make default copy constructors and assignment operators for us, if we don't declare them ourselves. So, if we DO declare them (we don't need to provide an implementation) and make sure those declarations are private, then the compiler will issue a compile-error if the programmer attempts to do just that.
In C++03, declaring a copy constructor and assignment operator with no definition as private is a way to prevent people from being able to copy instances of your class. If anyone attempts to do so, they'll get a compile error complaining that the assignment operator and copy constructor are private. Additionally by providing no definition if the class's own methods try to use the functions they will get a linker error complaining the operator and copy constructor are not defined. This is necessary because otherwise the compiler will generate a copy constructor and assignment operator for you, which often will not do what you want (a shallow copy).
In the new C++11 standard, there is a better way to do this. The delete keyword can be used in declarations like so:
struct NoCopy
{
NoCopy & operator =( const NoCopy & ) = delete;
NoCopy ( const NoCopy & ) = delete;
};
NoCopy a;
NoCopy b(a); //compilation error, copy ctor is deleted
Example taken from here.
Sometimes, making copies do not make sense (eg. a std::unique_ptr, a mutex object, or a database connection object, etc). Or making copies is inefficient, and you want to prevent this operation. Or implementing the copy constructor correctly is painful and fragile, and you'd prefer not to rely on its presence. Deleting the copy semantics is done by declaring the copy constructor private.
Another popular option is to inherit from boost::non_copyable.
The C++11 standard offers an alternative to the ubiquitous use of the copy constructor. This goes by the name of move semantics, and allows you to move objects instead of copying them. Move semantics pretty much always make sense: returning an object from a function moves it for instance. You can also explicitly move an object into some function taking its argument by value.
Note that C++11 in principle allows you to delete copy semantics in this way:
struct foo
{
foo(const foo&) = delete;
void operator=(const foo&) = delete;
};
instead of making them private, like in C++03.
Whenever I would have had to declare and implement a copy constructor, I nowadays find myself almost always disabling the copy semantics. With some habit, it makes sense: if copy semantics are not trivial, there is a chance that something is wrong with copying. One notable exception is reference counting though (see the class template std::shared_ptr).
I was reading some boost code, and came across this:
inline sparse_vector &assign_temporary(sparse_vector &v) {
swap(v);
return *this;
}
template<class AE>
inline sparse_vector &operator=(const sparse_vector<AE> &ae) {
self_type temporary(ae);
return assign_temporary(temporary);
}
It seems to be mapping all of the constructors to assignment operators. Great. But why did C++ ever opt to make them do different things? All I can think of is scoped_ptr?
why did C++ ever opt to make them do different things?
Because assignment works on a fully constructed object. In resource managing classes, this means that every member pointer already points to a resource. Contrast this to a constructor, where the members don't have any meaning prior to executing it.
By the way, in the very early days of C++, T a(b); was actually defined as T a; a = b;, but this proved to be inefficient, hence the introduction of the copy constructor.
Notice the name "assign_temporary" indicates that the assignment is from an object that is temporary and therefore can be destroyed in the process of assignment. The assignment operator takes some regular object that you might want to use later, so it is not an option to destroy it during the assignment. In this Boost code, "assign_temporary" is synonymous with the rvalue reference assignment operator, while the assignment operator that you have shown above is the standard const (lvalue) reference assignment operator, so you would, therefore, expect this kind of mismatch between the two.
I agree, though, the assignment operator is typically implemented using the copy and swap trick (create a copy with the copy constructor, then swap with the copy). However, the standard already defines the automatic implementation of the assignment operator by the compiler in the absence of an explicit definition, and so changing the default implementation would potentially break existing code.
For the very reason that some classes sometimes shouldn't be allowed to be assigned or even copied. For instance, using RAII you can build a mutex class which opens a lock and then closes the lock upon expiration. If you were allowed to copy or assign such a class you could conceivably pass it outside of the function scope. This could cause bad things in the hands of bad people.