Are non-static class members destroyed even without a destructor? - c++

In Bjarne Stroustrup's "The C++ Programming Language (4th edition)" in section 17.6 (Generating Default Operations) it mentions this:
If the programmer declares a copy operation, a move operation, or a
destructor for a class, no copy operation, move operation, or
destructor is generated for that class.
Thus, I'm confused why the SubObj destructor is called in this program:
#include <iostream>
using namespace std;
class SubObj {
public:
~SubObj() {
cout << "SubObj Destructor called" << endl;
}
};
class Obj {
private:
SubObj so;
public:
Obj() {};
Obj(const Obj& o) {};
};
int main() {
Obj();
cout << "Program end" << endl;
}
When compiling with g++ I get the following output:
$ ./a.out
SubObj Destructor called
Program end
Based on my understanding, I expected the default destructor for Obj to not be auto-generated because I defined a copy operation for Obj. And thus, I expected that the SubObj member of Obj would not be destroyed because there is no destructor for Obj.
Thus, I'm wondering: are object members automatically destroyed even without a destructor? Or is a destructor somehow being auto-generated for this example?
Edit:
Later in the book (17.6.3.4), when referring to an example, Bjarne mentions:
We defined copy assignment, so we must also define the destructor.
That destructor can be =default because all it needs to do is to
ensure that the member pos is destyored, which is what would have
been done anyway had the copy assignment not been defined.
Based on the answers so far, it sounds appears as though Bjarne may have just been wrong on this one.

That phrase from the book is poorly worded/wrong.
Of course a destructor is still generated if you provide a copy constructor. If it weren't, your program would not be able to be compiled.
If you provide your own destructor, a destructor is not generated. It doesn't need to be, and you can't have two.
Also, members are destroyed regardless of what your destructor does. A destructor allows you to do "extra" stuff, on top of the normal rules for object (and subobject) lifetime. There was never a risk that the SubObj member wouldn't be destroyed.

Bjarne's wording could have been better here. What
If the programmer declares a copy operation, a move operation, or a destructor for a class, no copy operation, move operation, or destructor is generated for that class.
Could more accurately be (but is still wrong, see the link below for the full rules)
If the programmer declares a copy operation, a move operation, or a destructor for a class, no copy operation, move operation, or destructor (respectively) is generated for that class.
meaning if you declare any of those special member functions, the compiler will not add it's own version. If you declare a copy constructor, it does not stop the destructor, only the copy constructor (and move in C++11+). Only defining a destructors stops the compiler from generating one. To see all of the rules see: What are all the member-functions created by compiler for a class? Does that happen all the time?

I do not have this book to check what is actually written here, but either you are quoting it incorrectly, or it is inaccurate (the latter is hard to believe). The other option is that it is just poorly phrased and confusing.
The only time when compiler will not generate an implicit destructor is when it is explicit:
If no user-declared destructor is provided for a class type (struct,
class, or union), the compiler will always declare a destructor as an
inline public member of its class.
https://en.cppreference.com/w/cpp/language/destructor

Related

Autogenerated move constructors causing illegal behavior

I asked a question about move constructors for which I haven't accepted an answer yet because I'm feeling more confused about certain aspects of the question even as I'm starting to get a grip on others. In particular, I've found a surprising case in which both g++ and clang++ generate incorrect move-constructors.
Question summary
g++ and clang++ apparently violate the rule that move-constructors are not generated when destructors are explicitly defined; why? Is this a bug, or am I misunderstanding what's going on?
For correctness, these (possibly-illegal) move constructors should invalidate RHS pointer members, but they don't. Why not?
It appears that the only way to avoid the unwanted behavior is to explicitly define a correct move constructor for every class that uses delete in its destructor. Does the Qt library (version 5.4) do this?
Part 1: Illegally auto-generated constructors?
Consider the following code:
class NoMove
{
public:
~NoMove() {}
};
int main()
{
std::cout << "NoMove move-constructible? " <<
std::is_move_constructible<NoMove>::value << std::endl;
}
Compiled with both g++ 4.9.2 and clang++ 3.5.1, this code prints:
NoMove move-constructible? 1
...But since NoMove has an explicitly defined destructor, I would expect that neither a move constructor nor a copy constructor should be auto-generated. Note that the unexpected constructor generation is not due to the fact that the destructor is trivial; I get the same behavior when the destructor delete[]s an array (!!), and I am even able to compile code that requires a valid move constructor (!!!!!). (See example below.) What's going on here? Is it legal to auto-generate a move constructor here, and if so, why?
Part 2: (Possibly illegal) auto-generated constructors causing undefined behavior?
It appears that providing safe move constructors when delete is involved is fairly simple, but I just want to make sure I understand: when a class contains a pointer member and owns the underlying data, is there any case in which it wouldn't be correct and sufficient for the move constructor to invalidate the RHS pointer after setting the destination pointer to the old value?
Consider the following example, which is similar to the NoMove example above and is based on my original question:
class DataType
{
public:
DataType()
{
val = new int[35];
}
~DataType()
{
delete[] val;
}
private:
int* val;
};
class Marshaller
{
public:
Marshaller()=default;
DataType toDataType() &&
{
return std::move(data);
}
private:
DataType data;
};
void DoMarshalling()
{
Marshaller marshaller;
// ... do some marshalling...
DataType marshalled_data{std::move(marshaller).toDataType()};
}
This compiles just fine--showing that, yes, DataType has an auto-generated move constructor. And of course, when run, it causes a double-deletion error.
Now, this would be okay, if the auto-generated move constructor invalidated the RHS pointer. So, if it's okay to auto-generate a move constructor here, why isn't that done safely? The move constructor that makes this work is simply:
DataType(DataType&& rhs) :
val{rhs.val}
{
rhs.val = nullptr;
}
(Right? Am I missing anything? Should it perhaps be val{std::move(rhs.val)}?)
This seems like it would be a perfectly safe function to auto-generate; the compiler knows that rhs is an r-value because the function prototype says so, and therefore it's entirely acceptable to modify it. So even if DataType's destructor didn't delete[] val, it seems like there wouldn't be any reason not to invalidate rhs in the auto-generated version, except, I suppose, for the fact that this leads to a trivial performance hit.
So if the compiler is auto-generating this method--which, again, it shouldn't, especially since we can just as easily get this exact behavior from standard library code using unique_ptr-- why is it auto-generating it incorrectly?
Part 3: Avoiding this behavior in Qt (especially QByteArray in Qt 5.4)
Finally, a (hopefully) easy question: do Qt 5.4's heap-allocating classes such as QByteArray (which is what I'm actually using as the DataType in my original question) have correctly implemented move constructors, invalidating any moved-from owning pointer(s)?
I wouldn't even bother to ask, because Qt seems pretty solid and I haven't seen any double-deletion errors yet, but given that I was taken off guard by these incorrect compiler-generated move constructors, I'm concerned that it's quite easy to end up with incorrect move constructors in an otherwise-well-implemented library.
Relatedly, what about Qt libraries written before C++11 that don't have explicit move-constructors? If I can accidentally coerce an auto-generated move constructor that behaves erroneously in this case, does anyone know if compiling, say, Qt 3 with a C++11-compliant compiler causes undefined destruction behavior in use-cases like this?
The problem is that you are confusing is_move_constructible and "has a move constructor". is_move_constructible<T> doesn't test whether T has a move constructor. It tests whether T can be constructed from an rvalue of type T. And const T& can bind to a T rvalue.
What you are seeing is the autogenerated copy constructor T(const T&) doing its work - and failing miserably.
I would expect that neither a move constructor nor a copy constructor should be auto-generated.
Your link talks about the move constructor. It doesn't talk about the copy constructor, which is always implicitly declared if you don't declare it.
Now, if you declared a move operation, the implicitly declared copy constructor would be defined as deleted, but you didn't do that, so it's defined as defaulted and performs a memberwise copy. [class.copy]/p7:
If the class definition does not explicitly declare a copy
constructor, one is declared implicitly. If the class definition
declares a move constructor or move assignment operator, the
implicitly declared copy constructor is defined as deleted; otherwise,
it is defined as defaulted (8.4). The latter case is deprecated if the
class has a user-declared copy assignment operator or a user-declared
destructor.

Why does the compiler require a copying constructor, need and have moving one and doesn't uses any of them?

I've already tried to ask this question but I wasn't clear enough. So here is one more try. And I am very sorry for my English ;)
Let's see the code:
#include <iostream>
#include <memory>
using namespace std;
struct A {
unique_ptr<int> ref;
void printRef() {
if (ref.get())
cout<<"i="<<*ref<<endl;
else
cout<<"i=NULL"<<endl;
}
A(const int i) : ref(new int(i)) {
cout<<"Constructor with ";
printRef();
}
~A() {
cout<<"Destructor with";
printRef();
}
};
int main()
{
A a[2] = { 0, 1 };
return 0;
}
It can not be compiled because unique_ptr has deleted copying constructor.
Orly?!
This class DOES HAVE an implied moving constructor because unique_ptr has one.
Let's do a test:
#include <iostream>
#include <memory>
using namespace std;
struct A {
unique_ptr<int> ref;
void printRef() {
if (ref.get())
cout<<"i="<<*ref<<endl;
else
cout<<"i=NULL"<<endl;
}
A(const int i) : ref(new int(i)) {
cout<<"Constructor with ";
printRef();
}
// Let's add a moving constructor.
A(A&& a) : ref(std::move(a.ref)) {
cout<<"Moving constructor with";
printRef();
}
~A() {
cout<<"Destructor with";
printRef();
}
};
int main()
{
A a[2] = { 0, 1 };
return 0;
}
I've added a moving constructor and now the code can be compiled and executed.
Even if the moving constructor is not used.
The output:
Constructor with i=0
Constructor with i=1
Destructor withi=1
Destructor withi=0
Okay...Let's do one more test and remove the copying constructor (but leave the moving one).
I don't post the code, there only one line has been added:
A(const A& a) = delete;
You should trust me - it works. So the compiler doesn't require a copying constructor.
But it did! (a facepalm should be here)
So what's going on? I see it completely illogical! Or is there some sort of twisted logic I don't see?
Once more:
unique_ptr has a moving constructor and has a deleted copying constructor. Compiler requires copying constructor to be present. But in fact the compiler requires a moving constructor (even if it is not used) and doesn't require a copying (because it could be deleted). And as I see the moving constructor is (should be?) present impliedly.
What's wrong with that?
P.S. One more thing - if I delete the moving constructor the program could not be compiled. So the moving constructor is required, but not the copying one.Why does it require copy-constructor if it's prohibited to use it there?
P.P.S.
Big thanks to juanchopanza's answer! This can be solved by:
A(A&& a) = default;
And also big thanks to Matt McNabb.
As I see it now, the moving constructor is absent because unique_ptr doesn't have a copying one the class has a destructor (and the general rule is that default/copying/moving constructors and destructor could be generated by default only all together). Then the compiler doesn't stop at moving one (why?!) and falls back to copying one. At this point the compiler can't generate it and stops with an error (about the copy constructor) when nothing else can be done.
By the way it you add:
A(A&& a) = delete;
A(const A& a) = default;
It could NOT be compiled with error about 'A::A(A&& a)' deletion, There will be no fall back to copying constructor.
P.P.P.S The last question - why does it stop with error at the COPY constructor but not the MOVE constructor?!
GCC++ 4.7/4.8 says: "error: use of deleted function ‘A::A(const A&)’"
So it stops at copy constructor.
Why?! There should be 'A::A(A&&)'
Ok. Now it seems like a question about move/copy constrcutor choosing rule.
I've created the new more specific question here
This is called copy elision.
The rule in this situation is that a copy/move operation is specified, but the compiler is allowed to optionally elide it as an optimization, even if the copy/move constructor had side-effects.
When copy elision happens, typically the object is created directly in the memory space of the destination; instead of creating a new object and then copy/moving it over to the destination and deleting the first object.
The copy/move constructor still has to actually be present, otherwise we would end up with stupid situations where the code appears to compile, but then fails to compile later when the compiler decides not to do copy-elision. Or the code would work on some compilers and break on other compilers, or if you used different compiler switches.
In your first example you do not declare a copy nor a move constructor. This means that it gets an implicitly-defined copy-constructor.
However, there is a rule that if a class has a user-defined destructor then it does not get an implicitly-defined move constructor. Don't ask me why this rule exists, but it does (see [class.copy]#9 for reference).
Now, the exact wording of the standard is important here. In [class.copy]#13 it says:
A copy/move constructor that is defaulted and not defined as deleted is implicitly defined if it is odr-used (3.2)
[Note: The copy/move constructor is implicitly defined even if the implementation elided its odr-use (3.2, 12.2). —end note
The definition of odr-used is quite complicated, but the gist of it is that if you never attempt to copy the object then it will not try to generate the implicitly-defined copy constructor (and likewise for moving and move).
As T.C. explains on your previous thread though, the act of doing A a[2] = {0, 1}; does specify a copy/move, i.e. the value a[0] must be initialized either by copy or by move, from a temporary A(0). This temporary is able to undergo copy elision, but as I explain earlier, the right constructors must still exist so that the code would work if the compiler decides not to use copy elision in this case.
Since your class does not have a move constructor here, it cannot be moved. But the attempt to bind the temporary to a constructor of A still succeeds because there is a copy-constructor defined (albeit implicitly-defined). At that point, odr-use happens and it attempts to generate the copy-constructor and fails due to the unique_ptr.
In your second example, you provide a move-constructor but no copy-constructor. There is still an implicitly-declared copy-constructor which is not generated until it is odr-used, as before.
But the rules of overload resolution say that if a copy and a move are both possible, then the move constructor is used. So it does not odr-use the copy-constructor in this case and everything is fine.
In the third example, again the move-constructor wins overload resolution so it does not matter what how the copy-constructor is defined.
I think you are asking why this
A a[2] = { 0, 1 };
fails to compile, while you would expect it to compile because A may have a move constructor. But it doesn't.
The reason is that A has a member that is not copyable, so its own copy constructor is deleted, and this counts as a user declared copy constructor has a user-declared destructor.
This in turn means A has no implicitly declared move constructor. You have to enable move construction, which you can do by defaulting the constructor:
A(A&&) = default;
To check whether a class is move constructible, you can use is_move_constructible, from the type_traits header:
std::cout << std::boolalpha;
std::cout << std::is_move_constructible<A>::value << std::endl;
This outputs false in your case.
The twisted logic is that you are supposed to write programs at a higher abstraction level. If an object has a copy constructor it can be copied, otherwise it cannot. If you tell the compiler this object shall not be copied it will obey you and not cheat. Once you tell it that it can be copied the compiler will try to make the copy as fast as possible, usually by avoiding the copy constructor.
As for the move constructor: It is an optimization. It tends to be faster to move an object from one place to another than to make an exact copy and destroy the old one. This is what move constructors are for. If there is no move constructor the move can still be done with the old fashioned copy and destroy method.

why can't objects be created without a constructor?

why does creation of an object needs a constructor?
Even if I don't define a constructor a default constructor is generated ..but why a constructor necessary?
why can't objects be created without a constructor?
This is more of a discussion on terminology than a real argument about the behavior. As you mention, in some cases there is nothing to be done during construction, so there should be no need for a constructor, right? Well, there is the concept of a trivial-constructor which is a constructor that does not do anything at all. For the sake of the standard document, it is easier to treat everything as having a (possibly trivial) constructor than to have to provide all the cases and exceptions in all places where it currently just states 'constructor'.
Consider that every use of 'constructor' would have to be replaced by 'constructor or nothing if the type does not have any virtual functions or bases and no members that require the generation of a constructor'.
This is the same reason why all virtual functions are called overrider even the first one in the hierarchy that by definition does not override anything. This form of generalization makes the language slightly easier to interpret, although not too many people will claim that section 8.5 on initialization is simple...
Also note that, while all user defined types by definition have a constructor, the constructor is not required for the creation of objects. In particular for objects with trivial-constructor the lifetime starts when the memory for the object is allocated (the standard, knowing that trivial means nothing to be done does not even go through the hop of requiring that the constructor is run in that case.
3.8 [basic.life]/1
The lifetime of an object is a runtime property of the object. An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor. [ Note: initialization by a trivial copy/move constructor is non-trivial initialization. — end note ] The lifetime of an object of type T begins when:
-- storage with the proper alignment and size for type T is obtained, and
-- if the object has non-trivial initialization, its initialization is complete.
That second bullet used to read (C++03): if T is a class type with a non-trivial constructor (12.1), the constructor call has completed. Which more clearly stated that the constructor need not be executed. But the new wording expresses the intent in basically the same way. Only if the object has non-trivial initialization, the initialization needs to complete. For objects with trivial-constructor (trivial initialization) allocating the storage creates the object. Where does it matter?
struct T { int x; }; // implicitly defined trivial-constructor
T *p = static_cast<T*>(malloc(sizeof *p));
// *p is alive at this point, no need to do
T *q;
{ void *tmp = malloc(sizeof T);
q = new (tmp) T; // call constructor
}
In a way, this is a slightly philosophical question. You can think of a constructor as a subroutine that turns some uninitialized memory into an object. Or you can think of it as a language feature that makes initialization easier to follow, write, and understand. You could even answer the question circularly: why does creation of an object needs a constructor? Because that's what creation of an object is, in a sense. If you don't have a constructor, what you're creating isn't an object.
It may be that a particular constructor does nothing, but that's an implementation detail of that class. The fact that every class has a constructor means that the class encapsulates what initialization is necessary: to use the class safely, you don't need to know whether the constructor does anything. In fact, in the presence of inheritance, vtables, debug-tracking, and other compiler features, you might not even know whether the constructor does anything. (C++ complicates this slightly by calling some classes POD types, but the encapsulation holds as long as you don't need to know that something is of POD type.)
The invocation of a constructor defines the point at which an object is created. In terms of language semantics, when the constructor finishes, the constructed object exists: before that, the object does not exist, and it is an error to use it as if it did. This is why construction order (that is, the order that member object and base class sub-object constructors are called) is so important in C++ and similar languages: if your constructor can throw an exception, it's necessary to destroy exactly those objects that have been constructed.
To end up with a working program, the programmer, anyone who tries to understand the source code, the compiler and linker, the runtime library, and any other compilation tools, all need to have a shared idea of what the program means: the semantics of the program. Agreeing on the lifetime of an object—when the compiler can run extra code to help create it, and when you can safely use it—is actually a big part of this agreement. Constructors and destructors are part of defining this lifetime. Even if they happen to be empty sometimes, they provide a way for us to agree when an object is valid, thus making it easier (possible) to specify and understand the language.
Say you have a simple class :
class Foo
{
int bar;
}
What is the value of bar exactly? Maybe you don't care when your object gets its memory allocated, but the machine running your program needs to give it some value. That's what the constructor is for : initializing class members to some value.
Constructor is necessary to call the constructors on class members, except built-in types see
Parametrized Constructors can take arguments. For example:
class example
{
int p, q;
public:
example();
example(int a, int b); //parameterized constructor
};
example :: example()
{
}
example :: example(int a, int b)
{
p = a;
q = b;
}
When an object is declared in a parameterized constructor, the initial values have to be passed as arguments to the constructor function. The normal way of object declaration may not work. The constructors can be called explicitly or implicitly. The method of calling the constructor implicitly is also called the shorthand method.
example e = example(0, 50); //explicit call
example e(0, 50); //implicit call
This is particularly useful to provide initial values to the object.
Also you will find important stuff on this page :
http://en.wikipedia.org/wiki/Constructor_%28object-oriented_programming%29

Is the destructor called when a delegating constructor throws?

It is well known that if a constructor throws, then all fully constructed sub-objects will be destroyed in reverse order including member data and all kinds of base classes. The destructor does not get called for non-delegating constructors though. For a delegating constructor the object has been constructed when the constructor body is entered, but construction continues somewhat. Therefore the question arises whether the destructor of the class is called, if the delegating constructor throws an exception from within its body?
class X
{
public:
X();
X(int) : X() { throw std::exception(); } // is ~X() implicitely called?
~X();
};
The rule is that the destructor is called for all fully
constructed objects. The object is considered fully constructed
once any constructor has finished, including the delegated
constructor (even though the program continues in another
constructor).
The lifetime of an object begins when any constructor (i.e., in the
case of delegation, the ultimate target constructor) is successfully
completed. For the purposes of [C++03] §3.8, “the constructor call
has completed” means any constructor call. This means that an
exception thrown from the body of a delegating constructor will cause
the destructor to be invoked automatically.
source.
And here is a nice article about delegating constructors, should anybody want to read it.

Why can't one ctor call another ctor to initialize the object

class Foo {
public:
Foo() { Foo(1)}
Foo(int x, int y = 0):i(x) {}
private:
int i;
}
Can anybody give me some reasonas about can I do this? If not why?
Because the language specification doesn't allow it. Just the way the language is. Very annoying if you're used to Java or other languages that allow it. However, you get used to it after a while. All languages have their quirks, this is just one of C++'s. I'm sure the writers of the specs have their reasons.
Best way around this I've found is to make a common initialization function and have both constructors call that.
Something like this:
class Foo {
public:
Foo() {initialize(1);}
Foo(int nX) { initialize(nx); }
private:
void initialize(int nx) { x=nx; }
int x;
};
It's a language design choice.
A constructor is a one time (per-object) operation that creates a new object in uninitialized memory. Only one constructor can be called for an object, once it has completed the object's lifetime begins and no other constructor can be called or resumed on that object.
At the other end of its life a destructor can only (validly) be called once per object and as soon as the destructor is entered the object's lifetime is over.
A prinicipal reason for this is to make explicit when an object destructor will be run and what state it can expect the object to be in.
If a class constructor completes successfully then it's destructor will be called, otherwise the object's lifetime has never begun and the destructor will not be called. This guarantee can be important when an object acquires resources in its constructor that need to be released in its destructor. If the resource acquisition fails then the constructor will usually be made to fail; if the destructor ran anyway it might attempt to release an resource that had never been successfully acquired.
If you allow constructors to call each other it may not be clear if a calling or a called constructor is responsible for the resource. For example, if the calling constructor fails after the called constructor returns, should the destructor run? The called constructor may have acquired something that needs releasing or perhaps that was what caused the calling construtor to fail and the destructor shouldn't be called because the resource handle was never valid.
For simplicity of the destruction rules it is simpler if each object is created by a single constructor and - if created successfully - destroyed by a single destructor.
Note that in C++11 a constructor will be able delegate to a different constructor, but there are limitations that don't really relax the principal of one construction per object. (The prinicipal constructor can forward to a target constructor, but if it does it must not name anything else (base classes or members) in its initializer list. These will be initialized by the target constructor, once the target constructor returns the body of the prinicipal constructor will complete (further initialization). It is not possible to re-construct any bases or members, although it allows you to share constructor code between constuctors.)
You cant do this. See section 10.3: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3. You can try to do it but doing so will construct a new temp object (not this) and be destroyed once control moves on.
What you can do however is to create a private function that initializes variables, one that your default constructor or a parameterized constructor can both call.
There is a really hideous hack I have seen used to call another ctor. It uses the placement new operation on the this pointer. erk
Like this:
Class::Class(int x) : x_(x) {}
Class::Class() {
new (this) Class(0);
}
Class::Class(const Class &other) : x_(other.x_) {}
Class& operator=(const Class &other) {
new (this) Class(other);
return *this;
}
Note that I am not recommending this, and I don't know what horrible effects it might have on C++ structures like virtual base classes, etc. But I expect that there are some.
Although as per standards vendors are free to implement data binding in their own ways, if we consider the most popular implementation: this pointer, we can see a reason why this can't be implemented.
Assume you have a class:
class A
{
public:
A(){}
A(int a){}
} ;
With the this pointer implementation, this class would look something like:
class A
{
public:
A(A *this){}
A(A *this,int a){}
} ;
Typically you would create objects like this:
A ob ;
Now when compiler sees this, it allocates memory for this and passes the address of this allocated memory block to the constructor of A which then constructs the object. It would try to do the same every time for each constructor called.
Now when you try calling a constructor within another constructor, instead of allocating new memory the compiler should pass the current objects this. Hence inconsistency!
Then another reason which i see is that even though you might want to call a constructor within another, u would still want a constructor to call default constructors for all the objects within the class. Now if one constructor were to call another, the default construction should happen for the first constructor and not for the subsequent one's. Implementing this behavior means that there would be several permutations which need to be handled. If not, then degraded performance as each constructor would default construct all the objects enclosed.
This is what i can think of as possible reasons for this behavior and do not have any standards to support.