When are implicit move constructors not good enough? - c++

When are implicit move constructors not good enough?
Should I treat it like destructors and copy constructors, where it's generally only necessary if I manage my own memory?
Is the implicit move constructor good enough in this (very contrived) scenario:
class A
{
private:
B b;
std::string name;
public:
A();
std::string getName() const {
return name;
}
B getB() const {
return b;
}
};
class B
{
private:
std::vector list;
public:
B();
std::vector getList() const {
return list;
}
};

The answer here is based on result of Google search.
Quoting from Andrzej's C++ blog
>
When should I define move constructor for my class?
It greatly depends on what your class does and how it is implemented. First, for ‘aggregate’ classes, which only group other data for convenience/clarity, move constructors will be implicitly generated by the compiler. Consider the following class.
struct Country {
std::string name;
std::vector<std::string> cities;
};
In a typical C++ struct many special member functions — like copy constructor, copy assignment, destructor — are auto-generated. This also includes move constructor (and move assignment).
For more sophisticated classes, which encapsulate their implementation details, the answer is more interesting. One of the main goals of move semantics (move constructor, move assignment) is to give the compiler two tools for implementing value semantics (passing arguments by value, returning by value) for user defined types:
Making two identical objects out of one — it needs to be expensive.
Moving one object from one memory location to the other — it can be
made very fast.
If for your class it is possible to implement move constructor that would be faster than the copy constructor, you should implement it for run-time speed optimization purposes. We have seen how it can be implemented for vector in this link. However, it is not for all types that such move constructor, faster than a copy constructor, can be implemented. Consider the following matrix representation.
class Matrix {
std::complex<long double> data[1000][1000];
};
Because all memory required for matrix representation is declared in class scope (unlike in vector, which uses heap-allocated memory) there is no way to apply only a small number of assignments. We will need to do a copying for each array element. There is no point in defining move constructor, as it will be no faster than copying.
Another valid reason for providing your move constructor if you want to enable your type that is non-copyable (because it is RAII-like and represents a resource) to be still passed by value where copying is not required, and stored in STL containers. Such unique ownership semantics are explained in more detail in this link.

Obligatory Rule of Zero answer: design either classes that manage a single resource - and thus override move/copy/destructor/assignment - or classes that aggregate resource managers and need no overrides.

Related

Unique Pointers and The Rule of 3

I often find myself using unique pointers in C++ when I want polymorphic behaviour. I typically implement pure abstract classes something like the below:
class A {
public:
virtual A* clone() const = 0; // returns a pointer to a deep copy of A
// other methods go here
};
The clone method comes in handy when I want to embellish another class with its own instance of A, for example:
#include <memory>
class B {
private:
std::unique_ptr<A> a_ptr;
public:
// ctor
B(const A& a) {
a_ptr = std::unique_ptr<A>(a.clone());
//...
}
// copy ctor
B(const B& other) : B(*other.a_ptr) {}
};
I invariably end up implementing the copy constructor in B to avoid a compiler error (MSVC gives a vague message about attempting to reference a deleted function), which makes complete sense because of the unique pointer. My questions can be summarised as follows:
Do I actually need the copy constructor in B? Perhaps there's a better pattern that would allow me to avoid it altogether.
If yes to 1, can I stop there? Will I ever need to implement the other default functions? I.e. is there any scenario where I need a default constructor and destructor also?
In practice, whenever I feel I need to implement the default functions, I typically implement a move-constructor alongside the other three; I usually use the copy-and-swap-idiom (as per GManNickG's answer in this thread). I assume this wouldn't change anything, but maybe I am wrong!
Thanks a lot!
First, I think the signature of your clone function could be
virtual std::unique_ptr<A> clone() = 0;
as you want deep copies of A instances and exclusive ownership within B. Second, you indeed have to define a copy constructor for your class when you want it to be copyable. Same for an assignment operator. This is due to the fact that std::unique_ptr is a move-only type, which hinders the compiler to generate default implementations.
Other special member functions are not needed, though they might make sense. The compiler won't generate move constructor and move assignment operator for you (as you ship your own copy/assignment functions), though in your case, you can = default; them easily. The destructor can equally well be defined with = default;, which would be in line with the core guidelines.
Note that defining the destructor via = default should be done in a translation unit, as std::unique_ptr requires the full type do be known upon freeing its resource.
Whether you need a default constructor totally depends on how yo want to use the class B.
As #lubgr mentioned in his answer, You should return unique_ptr not a raw one from the clone function. Anyway, going to Your questions:
Do You need a copy constructor in B? Well it depends on Your use cases, but if You copy objects of class B You may need one. But as You said, You do it quite often, so it would be wise to consider more generic approach. One of these would be creating a wrapper for unique_ptr which would have copy constructor and which would make a deep copy of this pointer in this copy constructor.
Consider following example:
template<class T>
class unique_ptr_wrap {
public:
unique_ptr_wrap(std::unique_ptr< T > _ptr) : m_ptr(std::move(_ptr)){}
unique_ptr_wrap(const unique_ptr_wrap &_wrap){
m_ptr = _wrap->clone();
}
unique_ptr_wrap(unique_ptr_wrap &&_wrap){
m_ptr = std::move(_wrap.m_ptr);
}
T *operator->() const {
return m_ptr.get();
}
T &operator*() const {
return *m_ptr;
}
private:
std::unique_ptr< T > m_ptr;
};
This again depends on Your needs. I personally would recommend overloading move constructor as well, to make it use less dynamic allocations (but this may be premateure optimization which is root of all evil).

Move Semantics for POD-ish types

Is there any point implementing a move constructor and move assignment operator for a struct or class that contains only primitive types? For instance,
struct Foo
{
float x;
float y;
float z;
/// ... ctor, copy ctor, assignment overload, etc...
};
I can see that, if I had something more complex, like:
struct Bar
{
float x,y,z;
std::string Name;
};
where I'd rather move Name than copy it, a move ctor would make sense. However, "moving" a float doesn't (semantically) make sense to me.
Thoughts?
Even if you have that std::string member, it doesn't make sense to implement a move constructor. The implicit move constructor will already move each of the members, which in the case of float will just copy it, and in the case of std::string will move it.
You should only really need to provide a move constructor when your class is doing some of its own memory management. That is, if you're allocating memory in the constructor, then you'll want to transfer the pointer to that allocated memory during a move. See the Rule of Five.
It's possible to avoid this situation entirely if you always rely on smart pointers to handle your allocated memory for you. See the Rule of Zero.
Note that a fully conforming C++11/14 compiler (not current version of VS2013) should automatically generate move operations for your Bar struct:
struct Bar
{
float x,y,z;
std::string Name;
};
In general, you should write move operations explicitly only for direct resource managers, that act like "building blocks". When you assemble together building blocks in more complex classes, the compiler should automatically generate move operations (using member-wise moves).
No need for that. If there are only primitive types in a class/struct, then default constructor/assignment operator will actually do that.

How to have const members in stl container values in C++?

I like to make my C++ member variables const if they should not be changed once the object is constructed, however, sometimes they need to be modified by STL. For example, if I have a vector of my class with const members and I try to swap two elements in the vector, STL tries to use the default generated operator=() and fails because of the const member variables.
I feel like the operator=() is like a constructor in that the whole object is being created and thus would like some way to allow operator=() while still having my const member variables.
Is there anyway to do this in C++03? If not, what about in C++11, perhaps in-place construction is for this?
class Foo {
const int _id;
static int _generate_unique_id();
public:
Foo()
: _id(_generate_unique_id()) {
}
};
vector<Foo> foo_vector;
// Fill foo_vector with several entries:
// [...]
// Try to swap the first and second elements of the vector:
swap(*foo_vector.begin(), *(foo_vector.begin() + 1));
// The above fails to compile due to const member variable _id
// prohibits us from using the default assignment operator.
A solution for storing not assignable objects in standard library containers is storing (smart) pointers to the objects. Not always ideal, but workable.
For example, if I have a vector of my class with const members and I try to swap two elements in the vector, STL tries to use the default generated operator=() and fails because of the const member variables.
Implement the "big three and a half" (default and copy constructor, assignment operator and swap), with the assignment operator explicitly skipping the reassignment if _id.
What you want is a thing like the Java immutable idiom.
This is awesome with pointers (and thus, garbage collected languages) and less awesome with value-semantic languages like C++.
You have two solutions:
1 - Make your object immutable in the interface
The member is private (or it should be), so no one but the class itself (and its friends) can modify it. So all you need is to make sure no one does inside the class (which you control) and offer no way in the protected/public interface to leave others the power to do so.
TL;DR: Make your object non const. Don't modify it inside the class. Add a const getter. Remove the setter (if any).
2 - Use a std::unique_ptr<const Data>
Now we follow the Java idiom. The object is const, but the pointer can be reattributed, which is exactly what you want.
This is actually better than the const Data * member alternative because of its exception safety.
Bonus: Don't manually call the destructor to reconstruct again the object
There's an answer proposing that.
As mentionned first by sehe, don't do that.
Your point is to increase the quality of your code, which means your code will need to be exception safe, at one point or the other. And manually playing with your object lifetime will make it unusable in quality code.
Read Herb Sutter's article on the subject: http://www.gotw.ca/gotw/023.htm
const on members doesn't just prevent the programmer from modifying the value of the member during its lifetime; it also enables compiler optimisations by specifying that attempts to modify it are undefined behaviour (see const member and assignment operator. How to avoid the undefined behavior?).
One way to do what you want is to write a nonmodifiable container that gives semantic const while leaving you as the programmer the possibility of modifying the contained value:
template<typename T> class nonmodifiable {
T t;
public:
nonmodifiable(T t): t{std::move(t)} {}
operator const T &() const { return t; }
nonmodifiable &operator=(const nonmodifiable &) = delete;
};
You can now write:
class Foo {
nonmodifiable<int> _id;
// etc.
};
and because neither _id nor its contained value are const, use the destruct-placement new dance to reassign its value:
Foo &operator=(const Foo &foo) {
if (this != &foo) {
_id.~nonmodifiable<int>();
new (&_id) nonmodifiable<int>(foo._id);
}
return this;
}

C++ Collections Class

I'm self studying C++.
If you're making a Class which only has a member variable that is a collection of "X" objects, (whatever X may be) would having just a default constructor and a deconstructor be enough seems its purely dealing with a collection of objects? Thanks.
EDIT: Sorry should have been clearer. For a different example, if you have a class "Aclass" that has an int, a string and a vector of objects of another class, would you advise the "Aclass" class to have a constructor with parameters? ie Aclass(int i, string s); and do you need to have the vector in the constructor too? I'm a little confused. Thanks.
If by "collection of 'x' objects" you mean "a standard container of 'x' objects", and by "enough" you mean "enough not to worry about resource management" then yes. Same goes for any well-written container made by you or a third-party.
This is also assuming your X objects are handling their resources correctly. And that they have semantics that are compatible with the container you're putting them in.
Edit
You don't need a constructor like that if you are OK having an object filled with default values for everything. I.e. empty containers, zeroed members (or was it uninitialized? -_-), etc.
You only really need a custom constructor if your object will be in an invalid state without one or if you want some sort of custom logic to run.
You mean enough to handle memory correctly? Depends on the type X. For example, if you have a vector<string> data member, you don't have to do any manual memory management in your class.
For class you may write your own constructor, which shows, how to construct inner objects, i.e
class A{
string s;
int x;
A(string t):s(t), x(17){} // x is always 17 after construction
}
But if inner object is default-constructable, you may leave it's construction and it will be costruct by default.
A(int l):x(l){}
is equivalent to
A(int l):x(l), s(){}
(except for primitive types), that may contain trash by default
If you use default constructor of A, all inner objects will construct by default.
If by collection you mean standard library classes, you would need copy ctor and assignment operator= overloaded.
std::map and std::set would reqire an additional comparison operator< overloaded.
std::unorderd_map and std::unordered_set would need a std::hash specialized for your type.
Often you don't have to define a default constructor. The compiler will declare a default constructor implicitly if one is needed and no constructors are defined. Often it will be useful to define additional constructors (like the one you mention) in addition to the default one. In that case you need to define both:
class A
{
public:
string s;
int x;
// default constructor, no arguments
A(): x(), s() {}
// constructor
A(int i, string t): x(i), s(t) {}
}
int main()
{
A a1;
A a2(5, "text");
vector<A> ls;
return 0;
}
As pwned mentions, in order to use your class A in an STL container, e.g. vector, it is required that A has a default constructor as in the example (either user-defined or implicit).

Benefits of Initialization lists

Of what I know of benefits of using initialization list is that they provide efficiency when initializing class members which are not build-in. For example,
Fred::Fred() : x_(whatever) { }
is preferable to,
Fred::Fred() { x_ = whatever; }
if x is an object of a custom class. Other than that, this style is used even with built-in types for the sake of consistency.
The most common benefit of doing this is improved performance. If the expression whatever is the same type as member variable x_, the result of the whatever expression is constructed directly inside x_ — the compiler does not make a separate copy of the object.
With the other style, the expression whatever causes a separate, temporary object to be created, and this temporary object is passed into the x_ object's assignment operator. Then that temporary object is destructed at the ;. That's inefficient.
Question
Is there any efficiency gain in the following example with using initialization list.
I think there is no gain. The first version calls string's copy constructor and the other calls string's assignment operator (there isn't any temporary thats created). It that correct?
class MyClass
{
public:
MyClass(string n):name(n) { }
private:
string name;
};
class MyClass
{
public:
MyClass(string n)
{
name=n;
}
private:
string name;
};
The second version is calling string's default ctor and then string's copy-assignment operator -- there could definitely be (minor) efficiency losses compared to the first one, which directly calls c's copy-ctor (e.g., depending on string's implementation, there might be useless allocation-then-release of some tiny structure). Why not just always use the right way?-)
I think the only way to initialize const data members is in the initialization list
Eg. in the header:
class C
{
C();
private:
const int x;
int y;
}
And the in the cpp file:
C::C() :
x( 10 ),
y( 10 )
{
x = 20; // fails
y = 20;
}
It's a great way to initialize members that :
are const
don't have a default constructor (it's private)
Remember that there is a distinct difference between a copy constructor and an assignment operator:
the copy ctor constructs a new object using some other instance as a place to get initialization information from.
the assignment operator modifies an already existing object that has already been fully constructed (even if it's only by using a default constructor)
So in your second example, some work has already been done to create name by the time that
name=n;
is reached.
However, it's quite possible (especially in this simple example) that the work done is vanishingly small (probably just zeroing out some data members in the string object) and that the work is optimized away altogether in an optimized build. but it's still considered good form to use initializer lists whenever possible.
We can also perform the constructor delegation via the initialization list.