C++ inplace destructor compile warning - c++

I am using an inplace destructor in my code, similar to this stripped down piece of code:
#include <new>
#include <stdlib.h>
struct Node {
};
int main(int, char**) {
Node* a = reinterpret_cast<Node*>(malloc(sizeof(Node)));
new(a) Node;
Node* b = a;
b->~Node();
free(a);
}
Unfortunately this gives me a warning in Visual Studio 2015, both in Debug and Release:
warning C4189: 'b': local variable is initialized but not referenced
It compiles fine though in g++, even with -Wall. Any idea why I get the warning? Might this be a bug in the compiler? b is clearly used in the b->~Node() call.
It also seems to compile fine when I change the Node implementation to this:
struct Node {
~Node() {
}
};
But as far as I can say this should not make a difference.

There are no standards for compiler warning in C++. Hence each compiler can warn you wherever he wants, it is a matter of choice.
In your case the warning does make sense, since the default destructor may not consider as a reference (for example: all local variable are defaultly destroyed at the end of their scope).

Trivial destructor
The destructor for class T is trivial if all of the following is true:
The destructor is not user-provided (meaning, it is either implicitly declared, or explicitly defined as defaulted on its first declaration)
The destructor is not virtual (that is, the base class destructor is not virtual)
All direct base classes have trivial destructors
All non-static data members of class type (or array of class type) have trivial destructors.
A trivial destructor is a destructor that performs no action. Objects with trivial destructors don't require a delete-expression and may be disposed of by simply deallocating their storage.

Related

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

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

unrestricted union members lifetime during parent object construction

Normally you are responsible for lifetime of your unrestricted union members -- and typically you do it via in-place ctor/dtor calls. But, apparently, there is at least one case when compiler helps you -- in the code below, if object construction fails it's (previously constructed) union member gets automatically destroyed (at least in MSVC 2015), i.e. we never leak.
#include <string>
struct CanThrow
{
CanThrow() { throw 0; }
};
struct A
{
A() : str{} {} // note that we don't explicitly call str dtor here
~A() { str.~basic_string(); }
union { std::string str; };
CanThrow ct;
};
int main() { try{ A a; } catch(...) {} }
Disclaimer: this code compiles on my MSVC 2015
Question -- is this guaranteed by standard and where it stipulates that?
Quite the contrary: it's not supposed to happen!
[C++11: 9.5/8]: A union-like class is a union or a class that has an anonymous union as a direct member. A union-like class X has a set of variant members. If X is a union its variant members are the non-static data members;
otherwise, its variant members are the non-static data members of all anonymous unions that are members of X.
[C++11: 15.2/2]: An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects (excluding the variant members of a union-like class), that is, for subobjects for which the principal constructor (12.6.2) has completed execution and the destructor has not yet begun execution. Similarly, if the non-delegating constructor for an object has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. If the object was allocated in a new-expression, the matching deallocation function (3.7.4.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object.
If Visual Studio is doing so, it's non-compliant; FWIW, GCC 6.3 seems to be also.
Note that the (current) C++17 wording is different and does permit what we're observing; this change appears to have been introduced by CWG issue #1866 in 2014, so it's likely that this is one of those times that the main compilers were "ahead of the game" and don't quite abide to the standard (despite -std flags).
So the answer is, no, the standard certainly doesn't guarantee it in MSVS 2015's case, though it will in future, C++17 versions of the software.

shared_ptr member and copy constructors

I'm writing a C++ library and would like one of its classes to be implicitly shared. Unfortunately I'm getting a bit confused with its implementation. I want to use std::shared_ptr to store the data and I'm wondering if the code below is missing anything.
// MyClass.h
class MyClass
{
public:
MyClass (void);
private:
class Data;
std::shared_ptr<Data> mData;
};
// MyClass.cc
class MyClass::Data
{
public:
Data (void) { ptr = NULL; }
~Data (void) { delete ptr; }
int* ptr;
};
MyClass::MyClass (void)
: mData (new MyClass::Data())
{
mData->ptr = new int(5);
}
Looking at other people's code I noticed they added copy/move constructors/operators (using std::move, etc) and an empty destructor. One of the comments mentioned that MyClass needs an empty destructor so that MyClass::Data's destructor gets noticed by the compiler. Is any of this really necessary or is the above code good enough? are the default copy/move constructors/operators and destructors good enough?
Your code is fine. You might want to declare a copy constructor in case you want to deep-copy the data, but that kind of defeats the purpose of using a shared pointer.
The empty destructor comment is complete BS. If you don't provide a destructor, a default one will be used - in any case the destructors of the member classes will always be called.
When you see people needing to explicitly default their destructors (and assignment operators) in MyClass.cc, that's because they're using std::unique_ptr instead of std::shared_ptr. If you switch to using std::unique_ptr<Data>, you'll see the compiler-provided destructor etc. will barf when they can't find a definition for ~Data in scope. But std::shared_ptr is not allowed to barf.

What's the compiler's freedom for destructor elision?

It's well known that, under certain conditions, the compiler might elide calls to the copy constructor. However, the Standard is clear saying that the compiler only has the freedom to change the runtime behavior (calling or not the copy constructor) but translation is performed as if the copy constructor is called. In particular, the compiler checks whether there's a valid copy constructor to call.
I came across a situation where a destructor call might be elided but compilers differ on whether a valid destructor needs to exist or not.
Here is a complete example showing how this issue might occur and how compilers differ in behavior.
template <typename T>
struct A {
~A() { (void) sizeof(T); }
};
struct B; // defined elsewhere.
struct C {
A<B> x, y;
~C(); // defined in a TU where B is complete.
};
int main() {
C c;
}
When compiling main() the compiler generates C's default constructor. This constructor default initializes first x and then y. If an exception is thrown during y construction, then x must be destroyed. The generated code looks like this:
new ((void*) &this->x) A<B>; // default initializes this->x.
try {
new ((void*) &this->y) A<B>; // default initializes this->y.
}
catch (...) {
(this->x).~A<B>(); // destroys this->x.
throw;
}
Knowing that A<B>'s default constructor is trivial (and doesn't throw), under the as-if rule, the compiler might simplify the code to:
new ((void*) &this->x) A<B>; // default initializes this->x.
new ((void*) &this->y) A<B>; // default initializes this->y.
Therefore, there's no need to call ~A<B>(). (Actually, the compiler can even remove the two initializations above since the A<B>'s constructor is trivial, but this is not important to this discussion.)
The question is: Even though the call to the destructor might be elided, should the compiler verify whether a valid destructor is available? I couldn't find anything on the Standard that clarifies the matter. Can anyone provide relevant quotes?
If the compiler decides to not translate ~A<B>() (like gcc and Visual Studio do) then the compilation succeeds.
However, if the compiler decides to translate ~A<B>() anyway (like clang and icc do), then it raises an error because here B is an incomplete type and its size cannot be taken.
I don't think this is specified by the standard. If ~A<B> is instantiated then it is ill-formed and a diagnostic is required. And as you say if constructing y throws, then x must be destroyed.
However, constructing y can never throw, so arguably there will never be a requirement for the destructor's definition to exist (15.2/2, 14.7.1/3).

C++ static initialization vs __attribute__((constructor))

Example:
struct Foo { Foo() { printf("foo\n"); } };
static Foo foo;
__attribute__((constructor)) static void _bar() { printf("bar\n"); }
Is it deterministic wether foo or bar is printed first?
(I hope and would expect that constructors of static objects are always executed first but not sure and GCCs doc about the constructor attribute doesn't say anything about it.)
foo will be printed first, as the objects are initialized in the order of their declarations. Run and see:
Ideone online demo
By the way, __attribute__((constructor)) is not Standard C++. It is GCC's extension. So the behavior of your program depends on how GCC has defined it. In short, it is implementation-defined, according to it foo is printed first.
The doc says,
The constructor attribute causes the function to be called automatically before execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () has completed or exit () has been called. Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.
You may provide an optional integer priority to control the order in which constructor and destructor functions are run. A constructor with a smaller priority number runs before a constructor with a larger priority number; the opposite relationship holds for destructors. So, if you have a constructor that allocates a resource and a destructor that deallocates the same resource, both functions typically have the same priority. The priorities for constructor and destructor functions are the same as those specified for namespace-scope C++ objects (see C++ Attributes).
I think the text in bold implies, the objects are initialized in the order of their declarations, as I said before, which is pretty much confirmed by online demo also.
I guess you would also like to read this:
7.7 C++-Specific Variable, Function, and Type Attributes
If you want to control/alter the initialization order, you can use init_priority attribute, providing priority. Taken from the page:
Some_Class A __attribute__ ((init_priority (2000)));
Some_Class B __attribute__ ((init_priority (543)));
Here, B is initialized before A.
It isn't defined by the standard, but here is my experiment https://github.com/SanSanch5/static-initialization-order-example
The output on gcc-9:
CFoo constructed
dll constructor
CBaz constructed
CBar constructed
foo
dll destructor
CBar destructed
CBaz destructed
CFoo destructed
The output on clang-12:
CFoo constructed
dll constructor
CBaz constructed
CBar constructed
foo
CBar destructed
dll destructor
CBaz destructed
CFoo destructed
So, the dll constructor is being called before static initialization, but as you can see, the destruction is slightly different on gcc and clang. But initializing a static object inside a dll constructor experimentally proves its destruction after the other static objects. But it's non-standard so not reliable.