Is this considered as bad style (doing new in the header outside of a construcor)?
class ClassName : public QWidget
{
Q_OBJECT
public:
explicit ClassName(QWidget* parent = 0);
CustomList<Identifier*>*const identifier_list = new CustomList<Identifier*>("someString");
};
What I want to achieve by this is to not have to write if (identifier_list == NULL) everywhere. Like this the identifier_list cannot be NULL.
That will of course only work in C++11 and above, due to the default member initializer. However, by writing this, you are now required to provide (or =delete) your copy/move constructors and assignment operators. Not to mention a destructor to delete this memory.
Which means you must decide on what copying behavior you want to have. Do you want to allow copying at all (and if not, you must use =delete to signify that)? If so, what should a copy do? Since it's a pointer-const, you can't copy the pointer itself. At least, not in the copy-assignment case. So if you're copying, you now must copy the pointed-to object.
And thanks to your pointer-const, movement is flat-out impossible (without a const_cast). So your move constructor/assignment will have to move the CustomList<Identifier*> object, not merely the pointer to it.
Also, because of all of these user-defined operations, your ClassName will no longer be considered a trivially copyable type. Though given that it stores a linked list, it probably wouldn't be trivially copyable either way.
So is this considered bad style? All things being equal, yes. Unless you have a genuine, well-considered reason to use a dynamic allocation, it's better and ultimately much safer programming style to just make it a value rather than a pointer:
CustomList<Identifier*> identifier_list("someString");
Related
To my knowledge, in theory, if a class has a raw pointer member, then the default copy constructor will do a shallow copy of that pointer, such that when the original object is destroyed, the pointer member in the copy will have had the value to which it pointed deleted. This seems to imply that outside of the case where we want to restrict copying for some reason, any class with a raw pointer member should define a copy constructor to do a deep copy on that pointer.
I am working with a respectable third party API, and I've come across a class with a raw pointer member, but no defined copy constructor, which casts doubt on my understanding above. Am I missing something?
UPDATE: The third party informed me that this class is not meant to be copied, as the object represents a visual element. They noted that they should have made a private copy constructor.
I think std::reference_wrapper is part of a respectable API (the C++ standard library). It has a copy constructor but that's not necessarily explicitly defined in the implementation code, because it just copies the raw pointer. So there you are: having a pointer member doesn't always imply ownership.
As a counter-example, an example of where you have non-owning pointer member but still need to take charge of copying, an object can contain a pointer to a part of itself. It would be ungood if copying such an object resulted in its internal pointer pointing to a part of some other object.
In summary, it depends. Must often you need a defined copy constructor. But absolutely not always.
For C++03 the law of three (or "rule of three") was a rule of thumb that if you needed either a destructor, a copy assignment operator or a copy constructor, then you probably needed all three.
So check if there is a copy assignment operator or destructor. In that case a copy constructor is probably required, and missing.
In C++11 and later some people extend it to the law of five, by including move assignment operator and move constructor, and some people reduce to the law of zero, by requiring that all ownership should be expressed via smart pointers or collection objects.
In an ideal world, any raw pointer member could be assumed to be a non-owning pointer. Since, if you had wanted an owning pointer you would have used a smart pointer!
A non-owning pointer member will point at an object whose lifetime is managed outside of the class and should be (by design) longer than the lifetime of the pointer.
The default behaviour when you copy the class is for the copy to also point at the same object. Often that is the behaviour you want. If not, yes, you will have to change that behavior.
Of course, we don't live in an ideal world and there are many places where owning raw pointer members are used. In that case, you are right, the default copy constructor is not appropriate (see Alf's answer regarding the rule of 3/5).
No, you're not missing anything. In general.
I'm hesitant to make any specific guarantees without knowing what library you're talking about and what the semantics of that class are (documented or otherwise) but, on the surface of it, this sounds like a library bug.
It's possible that the class doesn't own the pointee. This will likely be the case if its constructor doesn't allocate it, and its destructor doesn't de-allocate it.
Barring that, though, you're right.
Copy constructors were traditionally ubiquitous in C++ programs. However, I'm doubting whether there's a good reason to that since C++11.
Even when the program logic didn't need copying objects, copy constructors (usu. default) were often included for the sole purpose of object reallocation. Without a copy constructor, you couldn't store objects in a std::vector or even return an object from a function.
However, since C++11, move constructors have been responsible for object reallocation.
Another use case for copy constructors was, simply, making clones of objects. However, I'm quite convinced that a .copy() or .clone() method is better suited for that role than a copy constructor because...
Copying objects isn't really commonplace. Certainly it's sometimes necessary for an object's interface to contain a "make a duplicate of yourself" method, but only sometimes. And when it is the case, explicit is better than implicit.
Sometimes an object could expose several different .copy()-like methods, because in different contexts the copy might need to be created differently (e.g. shallower or deeper).
In some contexts, we'd want the .copy() methods to do non-trivial things related to program logic (increment some counter, or perhaps generate a new unique name for the copy). I wouldn't accept any code that has non-obvious logic in a copy constructor.
Last but not least, a .copy() method can be virtual if needed, allowing to solve the problem of slicing.
The only cases where I'd actually want to use a copy constructor are:
RAII handles of copiable resources (quite obviously)
Structures that are intended to be used like built-in types, like math vectors or matrices -
simply because they are copied often and vec3 b = a.copy() is too verbose.
Side note: I've considered the fact that copy constructor is needed for CAS, but CAS is needed for operator=(const T&) which I consider redundant basing on the exact same reasoning;
.copy() + operator=(T&&) = default would be preferred if you really need this.)
For me, that's quite enough incentive to use T(const T&) = delete everywhere by default and provide a .copy() method when needed. (Perhaps also a private T(const T&) = default just to be able to write copy() or virtual copy() without boilerplate.)
Q: Is the above reasoning correct or am I missing any good reasons why logic objects actually need or somehow benefit from copy constructors?
Specifically, am I correct in that move constructors took over the responsibility of object reallocation in C++11 completely? I'm using "reallocation" informally for all the situations when an object needs to be moved someplace else in the memory without altering its state.
The problem is what is the word "object" referring to.
If objects are the resources that variables refers to (like in java or in C++ through pointers, using classical OOP paradigms) every "copy between variables" is a "sharing", and if single ownership is imposed, "sharing" becomes "moving".
If objects are the variables themselves, since each variables has to have its own history, you cannot "move" if you cannot / don't want to impose the destruction of a value in favor of another.
Cosider for example std::strings:
std::string a="Aa";
std::string b=a;
...
b = "Bb";
Do you expect the value of a to change, or that code to don't compile? If not, then copy is needed.
Now consider this:
std::string a="Aa";
std::string b=std::move(a);
...
b = "Bb";
Now a is left empty, since its value (better, the dynamic memory that contains it) had been "moved" to b. The value of b is then chaged, and the old "Aa" discarded.
In essence, move works only if explicitly called or if the right argument is "temporary", like in
a = b+c;
where the resource hold by the return of operator+ is clearly not needed after the assignment, hence moving it to a, rather than copy it in another a's held place and delete it is more effective.
Move and copy are two different things. Move is not "THE replacement for copy". It an more efficient way to avoid copy only in all the cases when an object is not required to generate a clone of itself.
Short anwer
Is the above reasoning correct or am I missing any good reasons why logic objects actually need or somehow benefit from copy constructors?
Automatically generated copy constructors are a great benefit in separating resource management from program logic; classes implementing logic do not need to worry about allocating, freeing or copying resources at all.
In my opinion, any replacement would need to do the same, and doing that for named functions feels a bit weird.
Long answer
When considering copy semantics, it's useful to divide types into four categories:
Primitive types, with semantics defined by the language;
Resource management (or RAII) types, with special requirements;
Aggregate types, which simply copy each member;
Polymorphic types.
Primitive types are what they are, so they are beyond the scope of the question; I'm assuming that a radical change to the language, breaking decades of legacy code, won't happen. Polymorphic types can't be copied (while maintaining the dynamic type) without user-defined virtual functions or RTTI shenanigans, so they are also beyond the scope of the question.
So the proposal is: mandate that RAII and aggregate types implement a named function, rather than a copy constructor, if they should be copied.
This makes little difference to RAII types; they just need to declare a differently-named copy function, and users just need to be slightly more verbose.
However, in the current world, aggregate types do not need to declare an explicit copy constructor at all; one will be generated automatically to copy all the members, or deleted if any are uncopyable. This ensures that, as long as all the member types are correctly copyable, so is the aggregate.
In your world, there are two possibilities:
Either the language knows about your copy-function, and can automatically generate one (perhaps only if explicitly requested, i.e. T copy() = default;, since you want explicitness). In my opinion, automatically generating named functions based on the same named function in other types feels more like magic than the current scheme of generating "language elements" (constructors and operator overloads), but perhaps that's just my prejudice speaking.
Or it's left to the user to correctly implement copying semantics for aggregates. This is error-prone (since you could add a member and forget to update the function), and breaks the current clean separation between resource management and program logic.
And to address the points you make in favour:
Copying (non-polymorphic) objects is commonplace, although as you say it's less common now that they can be moved when possible. It's just your opinion that "explicit is better" or that T a(b); is less explicit than T a(b.copy());
Agreed, if an object doesn't have clearly defined copy semantics, then it should have named functions to cover whatever options it offers. I don't see how that affects how normal objects should be copied.
I've no idea why you think that a copy constructor shouldn't be allowed to do things that a named function could, as long as they are part of the defined copy semantics. You argue that copy constructors shouldn't be used because of artificial restrictions that you place on them yourself.
Copying polymorphic objects is an entirely different kettle of fish. Forcing all types to use named functions just because polymorphic ones must won't give the consistency you seem to be arguing for, since the return types would have to be different. Polymorphic copies will need to be dynamically allocated and returned by pointer; non-polymorphic copies should be returned by value. In my opinion, there is little value in making these different operations look similar without being interchangable.
One case where copy constructors come in useful is when implementing the strong exception guarantees.
To illustrate the point, let's consider the resize function of std::vector. The function might be implemented roughly as follows:
void std::vector::resize(std::size_t n)
{
if (n > capacity())
{
T *newData = new T [n];
for (std::size_t i = 0; i < capacity(); i++)
newData[i] = std::move(m_data[i]);
delete[] m_data;
m_data = newData;
}
else
{ /* ... */ }
}
If the resize function were to have a strong exception guarantee we need to ensure that, if an exception is thrown, the state of the std::vector before the resize() call is preserved.
If T has no move constructor, then we will default to the copy constructor. In this case, if the copy constructor throws an exception, we can still provide strong exception guarantee: we simply delete the newData array and no harm to the std::vector has been done.
However, if we were using the move constructor of T and it threw an exception, then we have a bunch of Ts that were moved into the newData array. Rolling this operation back isn't straight-forward: if we try to move them back into the m_data array the move constructor of T may throw an exception again!
To resolve this issue we have the std::move_if_noexcept function. This function will use the move constructor of T if it is marked as noexcept, otherwise the copy constructor will be used. This allows us to implement std::vector::resize in such a way as to provide a strong exception guarantee.
For completeness, I should mention that C++11 std::vector::resize does not provide a strong exception guarantee in all cases. According to www.cplusplus.com we have the the follow guarantees:
If n is less than or equal to the size of the container, the function never throws exceptions (no-throw guarantee).
If n is greater and a reallocation happens, there are no changes in the container in case of exception (strong guarantee) if the type of the elements is either copyable or no-throw moveable.
Otherwise, if an exception is thrown, the container is left with a valid state (basic guarantee).
Here's the thing. Moving is the new default- the new minimum requirement. But copying is still often a useful and convenient operation.
Nobody should bend over backwards to offer a copy constructor anymore. But it is still useful for your users to have copyability if you can offer it simply.
I would not ditch copy constructors any time soon, but I admit that for my own types, I only add them when it becomes clear I need them- not immediately. So far this is very, very few types.
I'm trying to understand the purpose of overloading some operators in C++.
Conceptually, an assignment statement can be easily implemented via:
Destruction of the old object followed by copy construction of the new object
Copy construction of the new object, followed by a swap with the old object, followed by destruction of the old object
In fact, often, the copy-and-swap implementation is the implementation of assignment in real code.
Why, then, does C++ allow the programmer to overload the assignment operator, instead of just performing the above?
Was it intended to allow a scenario in which assignment is faster than destruction + construction?
If so, when does that happen? And if not, then what use case was it intended to support?
1) Reference counting
Suppose you have a resource that is ref-counted and it is wrapped in objects.
void operator=(const MyObject& v) {
this->resource = refCount(v->resource);
}
// Here the internal resource will be copied and not the objects.
MyObject A = B;
2) Or you just want to copy the fields without fancy semantics.
void operator=(const MyObject& v) {
this->someField = v->someField;
}
// So this statement should generate just one function call and not a fancy
// collection of temporaries that require construction destruction.
MyObject A = B;
In both cases the code runs much faster. In the second case the effect is similar.
3) Also what about types...
Use the operator to handle assigning other types to your type.
void operator=(const MyObject& v) {
this->someField = v->someField;
}
void operator=(int x) {
this->value = x;
}
void operator=(float y) {
this->floatValue = y;
}
first, note that "Destruction of the old object followed by copy construction of the new object" is not exception safe.
but re "Copy construction of the new object, followed by a swap with the old object, followed by destruction of the old object", that's the swap idiom for implementing an assignment operator, and it's exception safe if done correctly.
in some cases a custom assignment operator can be faster than the swap idiom. for example, direct arrays of POD type can't really be swapped except by way of lower level assignments. so there for the swap idiom you can expect an overhead proportional to the array size.
however, historically there wasn't much focus on swapping and exception safety.
bjarne wanted exceptions originally (if i recall correctly), but they didn't get into the language until 1989 or thereabouts. so the original c++ way of programming was more focused on assignments. to the degree that a failing constructor signalled its failure by assigning 0 to this… i think, that in those days your question would not have made sense. it was just assignments all over.
typewise, some objects have identity, and others have value. it makes sense to assign to value objects, but for identity objects one typically wants to limit the ways that the object can be modified. while this doesn't require the ability to customize copy assignment (only to make it unavailable), with that ability one doesn't need any other language support.
and i think likewise for any other specific reasons one can think of: probably no such reason really requires the general ability, but the general ability is sufficient to cover it all, so it lowers the overall language complexity.
a good source to get more definitive answer than my hunches, recollections and gut feelings, is bjarne's "the design and evolution of c++" book.
probably the question has a definitive answer there.
Destruction of the old object, followed by copy construction of
the new, will not usually work. And the swap idiom is
guaranteed not to work unless the class provides a special swap
function—std::swap uses assignment in its unspecialized
implementation, and using it directly in the assignment operator
will lead to endless recursion.
And of course, the user may want to do something special, e.g.
make the assignment operator private, for example.
And finally, what is almost certainly an overruling reason: the
default assignment operator has to be compatible with C.
Actually, after seeing juanchopanza's answer (which was deleted), I think I ended up figuring it out myself.
Copy-assignment operators allow classes like basic_string to avoid allocating resources unnecessarily when they can re-use them (in this case, memory).
So when you assign to a basic_string, an overloaded copy assignment operator would avoid allocating memory, and would just copy the string data directly to the existing buffer.
If the object had to be destroyed and constructed again, the buffer would have to be reallocated, which would be potentially much more costly for a small string.
(Note that vector could benefit from this too, but only if it knew that the elements' copy constructors would never throw exceptions. Otherwise it would need to maintain its exception safety and actually perform a copy-and-swap.)
It allows you to use assignment of other types as well.
You could have a class Person with an assignment operator that assigns an ID.
But besides that, you don't always want to copy all the members as they are.
The default assignment only does a shallow copy.
For example, if the class contains pointers, or locks, you dont always want to copy them from the other object.
Usually when you have pointers you want to use a deep copy, and maybe create a copy of the object that the pointers are pointed to.
And if you have locks, you want them to be specific to the object, and you don't want to copy their state from the other object.
It is actually a common practice to provide your own copy constructor and assignment operator if your class holds pointers as members.
I have used it often as a conversion constructor but with already existing objects. i.e assigning member variable type, etc to an object.
For standard copy constructors and assignment operators, I always think about implementing them or deleteing the defaults out of existence, if my class implements a destructor.
For the new move constructor and move operator, what is the right way to think about whether or not an implementation is necessary?
As a first pass of transitioning a system from pre-C++0x, could I just delete the default move constructor and move operator or should I leave them alone?
You don't have to worry about it, in the sense that when you user-declare a destructor (or anything else listed in 12.8/9), that blocks the default move constructor from being generated. So there's not the same risk as there is with copies, that the default is wrong.
So, as the first pass leave them alone. There may be places in your existing code where C++11 move semantics allow a move, whereas C++03 dictates a copy. Your class will continue to be copied, and if that caused no performance problems in C++03 then I can't immediately think of any reason why it would in C++11. If it did cause performance problems in C++03, then you have an opportunity to fix a bug in your code that you never got around to before, but that's an opportunity, not an obligation ;-)
If you later implement move construction and assignment, they will be moved, and in particular you'll want to do this if you think that C++11 clients of your class are less likely to use "swaptimization" to avoid copies, more likely to pass your type by value, etc, than C++03 clients were.
When writing new classes in C++11, you need to consider and implement move under the same criteria that you considered and implemented swap in C++03. A class that can be copied implements the C++11 concept of "movable", (much as a class that can be copied in C++03 can be swapped via the default implementation in std), because "movable" doesn't say what state the source is left in - in particular it's permitted to be unchanged. So a copy is valid as a move, it's just not necessarily an efficient one, and for many classes you'll find that unlike a "good" move or swap, a copy can throw.
You might find that you have to implement move for your classes in cases where you have a destructor (hence no default move constructor), and you also have a data member which is movable but not copyable (hence no default copy constructor either). That's when move becomes important semantically as well as for performance.
With C++11, you very rarely need to provide a destructor or copy semantics, due to the way the library is written. Compiler provided members pretty much always do fine (provided they are implemented correctly: MSVC forces you to implement a lot of move semantics by hand, which is very bothersome).
In case you have to implement a custom destructor, use the following approach:
Implement a move constructor, and an assignment operator taking by value (using copy&swap: note that you cannot use std::swap since it uses the assignment. You have to provide a private swap yourself). Pay attention to exception guarantees (look up std::move_if_noexcept).
If necessary, implement a copy constructor. Otherwise, delete it. Beware that non default copy semantics rarely make sense.
Also, a virtual destructor counts as a custom destructor: provide or delete copy + move semantics when declaring a virtual destructor.
Since they are used as an optimization you should implement them if the optimization is applicable to your class. If you can "steal" the internal resource your class is holding from a temporary object that is about to be destroyed. std::vector is a perfect example, where move constructor only assigns pointers to internal buffer leaving the temporary object empty (effectively stealing the elements).
Let's assume I have a c++ class that have properly implemented a copy constructor and an overloaded = operator. By properly implemented I mean they are working and perform a deep copy:
Class1::Class1(const Class1 &class1)
{
// Perform copy
}
Class1& Class1::operator=(const Class1 *class1)
{
// perform copy
return *this;
}
Now lets say I have this constructor as well:
Class1::Class1(Class1 *class1)
{
*this = *class1;
}
My question is would the above constructor be acceptable practice? This is code that i've inherited and maintaining.
I would say, "no", for the following reasons:
A traditional copy constructor accepts its argument as a const reference, not as a pointer.
Even if you were to accept a pointer as a parameter, it really ought to be const Class1* to signify that the argument will not be modified.
This copy constructor is inefficient (or won't work!) because all members of Class1 are default-initialized, and then copied using operator=
operator= has the same problem; it should accept a reference, not a pointer.
The traditional way to "re-use" the copy constructor in operator= is the copy-and-swap idiom. I would suggest implementing the class that way.
Personally, I don't think it's good practice.
For the constructor, it's hard to think of a place where an implicit conversion from a pointer to an object to the object itself would be useful.
There's no reason for the pointer to be to non-const, and if you have available pointer to the class it is not hard to dereference it, and so clearly state your intention of wanting to copy the object using the copy constructor.
Similarly, for the non-standard assignment operator why allow assignment from a pointer when correctly dereferencing at the call site is clearer and more idiomatic?
I believe a somewhat more important issue than what has been discussed so far is that your non-standard assignment operator does not stop the compiler from generating the standard one. Since you've decided that you need to create an assignment operator (good bet since you made the copy constructor), the default is almost certainly not sufficient. Thus a user of this class could fall prey to this problem during what would seem very basic and standard use of an object to almost anyone.
Objects and pointers to objects are two very different things. Typically, when you're passing objects around, you expect that they're going to be copied (though, ideally functions would take const refs where possible to reduce/eliminate unnecessary copies). When you're passing a pointer around, you don't expect any copying to take place. You're passing around a pointer to a specific object and, depending on the code, it could really matter that you deal with that specific object and not a copy of it.
Assignment operators and constructors that take pointers to the type - especially constructors which can be used for implicit conversion - are really going to muddle things and stand a high chance of creating unintended copies, which not only could be a performance issue, but it could cause bugs.
I can't think of any good reason why you would ever want to make the conversion between a pointer to a type and the type itself implicit - or even explicit. The built-in way to do that is to dereference the object. I suppose that there might be some set of specific circumstances which I can't think of where this sort of thing might be necessary or a good idea, but I really doubt it. Certainly, I would strongly advise against doing it unless you have a specific and good reason for doing so.