C++ Is constructing object twice using placement new undefined behaviour? - c++

I have come across some code which has horrified me.
Essentially it follows this pattern :
class Foo
{
public:
//default constructor
Foo(): x(0), ptr(nullptr)
{
//do nothing
}
//more interesting constructor
Foo( FooInitialiser& init): x(0), ptr(nullptr)
{
x = init.getX();
ptr = new int;
}
~Foo()
{
delete ptr;
}
private:
int x;
int* ptr;
};
void someFunction( FooInitialiser initialiser )
{
int numFoos = MAGIC_NUMBER;
Foo* fooArray = new Foo[numFoos]; //allocate an array of default constructed Foo's
for(int i = 0; i < numFoos; ++i)
{
new( fooArray+ i) Foo( initialiser ); //use placement new to initialise
}
//... do stuff
delete[] fooArray;
}
This code has been in the code base for years and it would seem has never caused a problem. It's obviously a bad idea since someone could change the default constructor to allocate not expecting the second construction. Simply replacing the second constructor with an equivalent initialisation method would seem the sensible thing to do. eg.
void Foo::initialise(FooInitialiser& init)
{
x = init.getX();
ptr = new int;
}
Although still subject to possible resource leaks, at least a defensive programmer might think to check for prior allocations in a normal method.
My question is:
Is constructing twice like this actually undefined behaviour/ outlawed by standard or simply just a bad idea? If undefined behaviour can you quote or point me to right place to look in the standard?

Generally, working with placement new in this way is not a good idea. Calling an initializer from the first new, or calling an initializer instead of placement new are both considered to be better form than the code you've provided.
However, in this case, the behaviour of calling placement new over an existing object is well defined.
A program may end the lifetime of any object by reusing the storage
which the object occupies or by explicitly calling the destructor for
an object of a class type with a non-trivial destructor. For an object
of a class type with a non-trivial destructor, the program is not
required to call the destructor explicitly before the storage which
the object occupies is reused or released; however, if there is no
explicit call to the destructor or if a delete-expression (5.3.5) is
not used to release the storage, the destructor shall not be
implicitly called and any program that depends on the side effects
produced by the destructor has undefined behavior.
So when this happens:
Foo* fooArray = new Foo[numFoos]; //allocate an array of default constructed Foo's
for(int i = 0; i < numFoos; ++i)
{
new( fooArray+ i) Foo( initialiser ); //use placement new to initialise
}
The placement new operation will end the lifetime of the Foo that was there, and create a new one in it's place. In many circumstances this could be bad, but given the way your destructor works, this will be fine.
Calling placement new on an existing object could be undefined behaviour, but it depends on the specific object.
This does not produce undefined behaviour, because you are not depending on the "side effects" produced by the destructor.
The only "side-effect" in the destructor of your object is to delete the contained int pointer, but in this case that object is never in a deletable state when placement new is called.
If it was possible for the contained int pointer to be equal to something other than nullptr and could possibly require deleting, then calling placement new over the existing object would invoke undefined behaviour.

Related

C++ custom delete

Let's say we have the following code:
class MyType
{
public: int x;
}
MyType* object = new MyType();
delete object;
Is there a possible to check if object has specific value of x before deletion?
For example, if object.x is odd number, the object should not be free from memory after delete is called. In a few words to make a custom delete for this class where we can choose when the object can be free at operator delete call.
What is the real issue you are trying to solve?
To begin with, this Q&A is a good lesson to the common scenario in C++ of:
The language allowing you to do something, but just because you can doesn't mean you should.
These scenarios are commonly run into when trying to solve an XY problem.
In this particular case, instead of trying to overload operator delete (solving the Y problem, to much confusion of the clients of MyType) you are likely looking for something entirely different (the X problem), say a resource manager that take responsibility of MyType resources w.r.t. if and when they should be deleted (or not), based on e.g. object traits (such as oddness of a data member). See e.g. #Ayxan Haqverdili's answer for a minimal example.
A look at theoretically solving the misidentified Y problem
Don't do this, ever, for this kind of use case.
You can overload operator delete (as well as operator delete[]), by defining it as a static member function of the class for which you want to overload it (lookup precedence by lexical scope). As pointed out in the comments, whilst overloading the usual deallocation functions is legal, trying to conditionally allow for it to be called more than once is not:
struct MyType final {
int x;
static void operator delete(void *p) {
if (static_cast<MyType *>(p)->x % 2 == 1) {
::operator delete(p);
}
}
};
int main() {
MyType *object = new MyType{42};
delete object; // Not DEALLOCATED.
// Underlying object DESTRUCTED, however.
// Extremely confusing.
++(object->x);
delete object; // UB: destructor for underlying object called twice.
}
as per [expr.delete]/6 [emphasis mine]:
If the value of the operand of the delete-expression is not a null pointer value and the selected deallocation function (see below) is not a destroying operator delete, the delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted.
As a second attempt (emphasis: don't ever go down this road), we could avoid the destructor being called (only calling it conditionally) by overloading and abusing the (new as of C++20) class-specific destroying deallocation functions:
#include <iostream>
#include <new>
struct MyType final {
int x;
static void operator delete(MyType *p, std::destroying_delete_t) {
if (p->x % 2 == 1) {
p->~MyType();
::operator delete(p);
}
}
~MyType() {
std::cout << "\ndtor";
}
};
int main() {
MyType *object = new MyType{42};
delete object; // Neither deallocated nor underlying object destructed.
++(object->x);
delete object; // Destructed and deallocated.
}
Afaict this program is well-formed, but it does abuse the new destroying delete overloads. Clang does emit a -Wmismatched-new-delete warning, which is typically a hint for UB, but it may be inaccurate here.
Anyway, this seems like a good place to stop the fruitless journey of addressing this particular Y problem.
Yes:
if (object->x % 2 == 1)
delete object;
Note that raw pointers should be used rarely and with a lot of care.

should the destructor be called with placement new even on the same type

#include <new>
struct X
{
~X() { std::cout << "destroyed" << std::endl; }
int x;
};
int main(int argc, const char * const * const argv)
{
X x{1};
new (&x) X{2};
std::cout << x.x << std::endl;
return 0;
}
Output
2
destroyed
What I know is that the destructor should always be called when placement new is used. However in this sample code, the destructor is implicitly called in the end of the main so calling it again is undefined behaviour I suppose.
so now I want to know if the destructor should always be called when placement new is used or are there certain conditions under which the destructor should not be called?
It's specified explicitly in the C++ standard
[basic.life]
5 A program may end the lifetime of any object by reusing the
storage which the object occupies or by explicitly calling the
destructor for an object of a class type with a non-trivial
destructor. For an object of a class type with a non-trivial
destructor, the program is not required to call the destructor
explicitly before the storage which the object occupies is reused or
released; however, if there is no explicit call to the destructor or
if a delete-expression is not used to release the storage, the
destructor shall not be implicitly called and any program that depends
on the side effects produced by the destructor has undefined behavior.
The last sentence leaves a little bit of wriggle room regarding the possibility of undefined behavior1. But ultimately, the only types for which this is well-defined are those for which the destructor is truly trivial.
1 - As of writing this, anyway.
What I know is that the destructor should always be called when placement new is used.
Yes, except when the type is trivially destructible.
In this case, you must destroy the previously constructed object before placement new:
X x{1};
x.~X();
try {
new (&x) X{2};
} catch(...) {
std::abort(); // no way to recover
}
An automatic variable of non-trivially destructible type must not go out of scope in a destroyed state. If the constructor throws, the behaviour will be undefined. Reusing memory of a non-trivial object is not recommended.
It is safer to reuse memory of a trivial object:
alignas(alignof(X)) std::byte arr[sizeof(X)];
new (arr) X{2};
x.~X();

why does the standard let me free-store allocate classes without destructors?

If you have a class without a destructor:
struct A {
~A() = delete;
};
The standard does not let me "locally" allocate an instance of that class:
int main()
{
A a; //error
}
But it seems like it is ok if I allocate that on free-store:
int main()
{
a *p = new A();
}
As long as I dont call delete on that pointer:
int main()
{
a *p = new A();
delete p; //error
}
So my question is, why does the standard let me have a class without a destructor if I allocate it on free-store? I would guess there are some use cases for that? But what exactly?
So my question is, why does the standard let me have a class without a destructor if I allocate it on free-store?
Because that's not how standard features work.
The = delete syntax you're talking about was invented to solve a number of problems. One of them was very specific: making types that were move-only or immobile, for which the compiler would issue a compile-time error if you attempted to call a copy (or move) constructor/assignment operator.
But the syntax has other purposes when applied generally. By =deleteing a function, you can prevent people from calling specific overloads of a function, mainly to stop certain kinds of problematic implicit conversions. If you don't call a function with a specific type, you get a compile-time error for calling a deleted overload. Therefore, =delete is allowed to be applied to any function.
And the destructor of a class qualifies as "any function".
The designed intent of the feature was not to make types which would be non-destructible. That's simply an outgrowth of permitting =delete on any function. It's not design or intent; it simply is.
While there isn't much use to applying =delete to a destructor, there also isn't much use in having the specification to explicitly forbid its use on a destructor. And there certainly isn't much use in making =delete behave differently when applied to a destructor.
With this:
A a;
You will call the destructor upon exiting the scope (and you have deleted the destructor, hence the error). With this:
A *a = new A();
You simply don't call the destructor (because you never use delete). The memory is cleaned up at the programs completion, but you are essentially guaranteeing a memory leak.
There is no reason for c++ to disallow this behavior because this would create a very specific case to program into a compiler. For example, c++ doesn't disallow this:
int *p; *p = 5;
Even though this is obviously bad, and will always be bad. It is up to the programmer to ensure they don't do this.
There is no reason that you should delete your destructor because it is not a useful behavior.
In a multi-threaded environment, you may be sharing the non-destructed class between threads.
If the thread that allocates memory terminates, there is no reason a pointer to that allocated memory couldn't still be in use by another thread.
The standard implies that a constructed object with dynamic storage duration does not qualify for destructor invocation.
12.4 Destructors [class.dtor]
A destructor is invoked implicitly
— for a constructed object with static storage duration at program termination,
— for a constructed object with thread storage duration
at thread exit,
— for a constructed object with automatic
storage duration when the block in which an object is created
exits,
— for a constructed temporary object when its
lifetime ends.
We can see the benefits of this through a basic memory sharing example between threads:
#include <thread>
#include <iostream>
//shared object
struct A {
void say_hello(){ std::cout << ++value << '\n'; }
~A() = delete;
int value;
};
//two threads
void creator();
void user(A* a);
//the creator allocates memory,
//gives it to another thread (via pointer),
//and then ends gracefully.
//It does not attempt to implicitly call the destructor.
//Nor would we want it to for allocated memory we are sharing.
void creator(){
A* a = new A();
a->value = 0;
std::thread t(user, a);
t.detach();
}
//The user recieves a pointer to memory,
//and is free to continue using it
//despite the creator thread ending
void user(A* a){
while(1){
a->say_hello();
}
}
//main->creator->user
int main(){
std::thread t(creator);
while(1){}
}

Is it dangerous to use placement new on an old object without explicitly calling the destructor first?

I would like to recycle memory for an object rather than deallocating and reconstructing it. Is the following usage of "placement new" safe, assuming that Foo in practice does not contain pointers (but might contain functions)?
Also, is the final delete call safe, and will it correctly call the destructor on the second "new" object, and correctly free the memory afterwards?
#include <new>
struct Foo {
int hello;
int world;
};
int main() {
Foo* foo = new Foo;
// Do something with foo
// Done with foo, writing a new version of foo on top of the old one.
new(foo) Foo();
delete(foo);
}
The simple example above compiles and runs without errors, but I cannot tell by running it whether it might blow up for some reason in a more complex environment.
It's safe because the object you're overwriting has a trivial destructor. From n3337, chapter 3.8 (Object lifetime):
4 A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly
calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type
with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage
which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a
delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and
any program that depends on the side effects produced by the destructor has undefined behavior.
The delete call is safe, too. You're calling it on a pointer that you got from new and there's a live object at that place.
And as you hinted in the question, it could invoke undefined behaviour if the destructor is non-trivial and has side effects - you need to call it explicitly in that case. Whether or not the class contains pointers is not directly important - reusing the storage is safe even in that case, but of course, you could introduce memory leaks and other bugs that way.
No, it is not dangerous to reuse memory of an object, provided that you are doing it correctly. Moreover, you do not have to restrict yourself to objects that have no pointers: by calling the destructor explicitly you can prepare the object for reuse, like this:
Foo* foo = new Foo;
// Do something with foo
// Done with foo, writing a new version of foo on top of the old one.
foo->~Foo(); // Call the destructor explicitly to clean up the resources of a Foo
new(foo) Foo(); // Place new data into the previously allocated memory
delete(foo); // We are deleting a fully initialized object, so it is OK
There have been two answers already, but they give, I fear, an incomplete picture.
You may reuse the storage of an object, providing that you respect a few conditions:
You need not use a dynamically allocated object, any object is fine.
You should properly destroy the previous object, by calling its destructor (explicitly); failure to do so leads to undefined behavior if the destructor has side-effects (see §3.8/4)
The object that you place should have the same dynamic type as the previous object (see §3.8/7)
Let us review them, starting with any object is fine:
struct Foo {
int hello;
int world;
};
void automatically_allocated() {
Foo foo;
foo.~Foo();
new (&foo) Foo{};
}
void dynamically_allocated() {
std::unique_ptr<Foo> foo(new Foo{});
foo->~Foo();
new (&*foo) Foo{};
}
Let use continue with destroy the previous object:
struct Bar {
int hello;
std::string world;
};
void UNDEFINED_BEHAVIOR() {
Bar bar;
new (&bar) Bar{}; // most likely scenario: leaks memory owned by bar.world
}
And finally with same dynamic type:
struct Base { virtual ~Base() {} };
struct Derived: Base { std::string world; };
struct Other: Base { int hello; }
void UNDEFINED_BEHAVIOR() {
Derived derived;
Base& b = derived;
b.~Base(); // fine
new (&b) Other{};
// Most likely here, calls "derived.~Derived()" on an object of type Other...
}

Destructor is called on unwanted object during assignment

myClassVar = MyClass(3);
I expected destructor being called on the previously created myClassVar on the left.
But it is actually being called on the new object that's created by MyClass(3).
My full test code and output follows..
edit
How do I fix the problem?
Implement an assignment operator?
MyClass actually has pointers, and MYSQL_STMT*, I wonder how should I deal with MYSQL_STMT* variable.
I just need MyClassVar(3) object not the MyClassVar() which was first created when ClientClass object was created.
I came across this situation fairly often, and wonder if there's a good way to do it.
#include <stdio.h>
class MyClass
{
public:
MyClass() { printf("MyClass %p\n", this); }
MyClass(int a) { printf("Myclass(int) %p\n", this); }
~MyClass() { printf("~MyClass %p\n", this); }
private:
int mA;
};
class ClientClass
{
public:
void Foo()
{
printf("before &myClassVar : %p\n", &myClassVar);
myClassVar = MyClass(3); // this is the important line
printf("after &myClassVar : %p\n", &myClassVar);
}
private:
MyClass myClassVar;
};
int main()
{
ClientClass c;
c.Foo();
return 0;
}
MyClass 0x7fff5fbfeba0
before &myClassVar : 0x7fff5fbfeba0
Myclass(int) 0x7fff5fbfeb70
~MyClass 0x7fff5fbfeb70 // <--- here destructor is called on the newly created object
after &myClassVar : 0x7fff5fbfeba0
~MyClass 0x7fff5fbfeba0
Here's how the critical line breaks down:
myClassVar = MyClass(3);
First, MyClass(3) calls constructor and returns the object.
Second, myClassVar = copies the object to myClassVar.
Then the statement ends. The object (which is an immediate) is dead, and thus the destructor is invoked.
EDIT :
As for how to get around this. The only way I can think of is to use a placement new. I'm not sure if there's a better solution other than making a "set" method.
myClassVar = MyClass(3);
myClassVar continues to exist after this line. The lifetime of MyClass(3) ends at the semicolon.
As the other posts mentioned the object with the custom constructor MyClass(3) gets destroyed after the assignment operation myClassVar = MyClass(3). In this case you do not need a custom assignment operator because the compiler generated one copies the member mA to the already existing object myClassVar.
However since MyClass defines its own destructor you should adhere to the rule of three, which mandates that in such a case you should implement a custom assignment operator as well.
Responding to your edit: how do you fix what problem? It's not clear
what the problem is. If your class needs a destructor (and there's no
polymorphism in play), it probably needs both an assignment operator and
a copy constructor. Similarly, when "tracking" construcctions and
destructions, you should probably provide both as well, since they will
be called.
Otherwise: if the problem is that you're constructing and then
assigning, rather than constructing with the correct value immediately,
the simple answer is "don't do it". The compiler does what you tell it
to. If you write:
MyClass var;
var = MyClass(3);
you have default construction, followed by the construction of a
temporary, assignment, and the destruction of the temporary. If you
write:
MyClass var(3);
or
MyClass var = 3;
you only have one construction. (Note that despite appearances, there
is no assignment in the last snippet. Only construction.)
For class members, this difference appears in the way you write the
constructor:
ClientClass::ClientClass() { var = MyClass(3); }
is default construction, followed by creation, assignment and
destruction of a temporary;
ClientClass::ClientClass() : var( 3 ) {}
is just construction with the correct value. (Rather obviously, this
second form is preferred.)