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).
Related
I'm writing a piece of code that inherits from a user provided class (not for polymorphism reasons).
I need to write an explicit move constructor/assignment for it because I store pointers to some internal data of my class.
I don't know how to call move constructor well.
Example:
template <typename UserType>
class my_class : UserType {
other_data data;
public:
my_class(my_class&& x) UserType(/*...*/), data(std::move(x.data)) {}
};
Options:
I can call move(x) => but then it's use after move.
I can do some static_cast<UserType&&>(x) - but that's quite unusual.
What's a good solution here?
As you most likely already know, std::move is equal to your static_cast. Hence, technically, there is no difference.
As the underlying move constructor only knows your base class, it will be safe to access your own members. I guess the best solution here is to simply use = default; and ensure that all special behavior gets pushed into a separate class that doesn't have to deal with special behavior you need.
Call move(x) is the most canonical way: the base move constructor would never mess up with the derive class members without invoking undefined behavior.
Note that "use after move" is usually legit, the c++ standard demands that "Unless otherwise specified, all standard library objects that have been moved from are placed in a valid but unspecified state." This means their member functions are still callable if they require no precondition. Consider this example:
vector<int> a = { 1, 2, 3 };
vector<int> b(std::move(a));
//std::cout << a.back(); <- Invalid call. We don't know whether a is empty.
a.clear(); // Ok. clear() doesn't require preconditions.
a.push_back(0); //Ok. Now a is { 0 }
Also, the validity of an object is usually required for a destructor call (which cannot be avoided if the object has automatic storage duration).
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.
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;
}
Lets say I have this class:
class X {
public:
int x;
};
I saw that if I create an instance of X locally, x will not be initialize to 0, only if I create it globally.
Does this mean that the default constructor isn't synthesized by the compiler(I doubt it) for objects created localy or it will be synthesized but not zero out x value, if this is the case why is that ?
Constructors in C++ don't generally initialize members to 0. You have to explicitly initialize members with a value.
The reason that in the global case the memory is zero, is because static memory gets initialized to zero before anything else happens to it. In your case, the implicitly generated default constructor gets called afterwards, which does not touch the memory for member X.
See also this answer from Derek: Is global memory initialized in C++?
Note, however, that default constructors for structured, non-POD members (classes and structs) do automatically get called by the default constructor. It's just the POD members that are left alone by default.
X gets a synthesised constructor, but synthesised constructors do not zero-initialise primitives.
You are combining the concept of object construction with member initialization. As a general rule, don't expect C++ to initialize primitive data members for you, you'll need to do that yourself (preferably via an initialization list after the constructor.)
This is primarily for speed, as this allows allocation without initialization, which is useful if, for instance, you will be computing the values of the data members later and overwriting any "default" values.
I've found this site a useful reference in the past: http://www.cplusplus.com/doc/tutorial/variables/
Default constructors are not aware that it should initialize your member variables. If you need to initialize x to something, you better add your own constructor to do this for you:
class X {
public:
X() : x(0) { };
int x;
};
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.