Placement new on non-pointer variables and class members - c++

Consider the following example:
#include <iostream>
struct A {
int i;
A(int i)
{
this->i = i;
}
A &operator=(const A &a) = delete;
A(const A &a) = delete;
};
int main()
{
A a(1);
new(&a) A(5);
//a = A(7); // not allowed since = is deleted in A
std::cout << a.i << std::endl;
}
This is a simple example using the placement new operator. Since the copy constructor and assignment operator of struct A have been deleted (for whatever reason), it is not possible to change the object the variable A a holds, except for passing its address to the placement new operator.
Reasons for this might include that struct A holds large arrays (e.g. 100M entries) which would have to be copied in the assignment operator and the copy constructor.
The first part of the question revolves around the "legality" of this approach. I found this stackoverflow question, the accepted answer of which says
this is perfectly legal.
And useless, because you cannot use var [A a in this case] to refer to the state of the [object] you stored within it after the placement new. Any such access is undefined behavior.
[…] under no circumstance may you ever refer to var after you placement new'd over it.
Why would that be the case? I have seen several other examples for the placement new operator, which are always similar to
A a(1);
A *b = new(&a) A(2);
// Now use *b instead of a
From my understanding it should not matter whether A a or A *b is used to access the object since the placement new replaces the object at the address of A a which of course is A a. That is, I would expect that always b == &a. Maybe the answer was not clear enough and this limitation is due to the const-ness of the class member.
Here is another example with the same idea, however this time struct A is embedded into another object:
#include <iostream>
struct A {
int *p;
A(int i)
{
p = new int(i);
}
~A()
{
delete p;
}
A &operator=(const A &a) = delete;
A(const A &a) = delete;
};
struct B {
A a;
B(int i) : a(i)
{
}
void set(int i)
{
a.~A(); // Destroy the old object
new(&a) A(i);
}
};
int main()
{
B b(1);
b.set(2);
std::cout << *(b.a.i) << std::endl;
// This should print 2 and there should be no memory leaks
}
The question is basically the same with the same reasoning. Is it valid to placement-new into the address &a?

For this specific code, you are okay and can use a to refer to the new object that you put in its place. This is covered by [basic.life]/8
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:
the storage for the new object exactly overlays the storage location which the original object occupied, and
the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
neither the original object nor the new object is a potentially-overlapping subobject ([intro.object]).
emphasis mine
You check off all of those requirements so a will refer to the "new" A that you placed in a's memory.

Related

Is it possible now with the current C++ standard draft version to define a copy assignment operator for classes with const fields without UB

Here on SO we have had a lot of questions about assignments to const fields and Undefined Behavior (UB). For example This accepted answer which says that is not possible to define a copy assignment operator for classes with const fields because of UB.
But I checked the current draft version of the C++ standard (N4861). The part which said it would be UB [basic.life.8] was:
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:...
the type of the original object is not const-qualified, and, if a class type, does not contain any non-static
data member whose type is const-qualified or a reference type, and
Has now been replaced with:
o1 is not a complete const object, and
My interpretation is, that the following code now has no UB. Is it right? I ask this because in the sample, there is no cv qualified member - so it's still not clear for me.
#include <iostream>
struct C {
const int i;
void f() const {
std::cout << i << "\n";
}
C(int i) : i(i) {}
C& operator=( const C& );
};
C& C::operator=( const C& other) {
if ( this != &other ) {
this->~C(); // lifetime of *this ends
new (this) C(other); // new object of type C created
f(); // well-defined
}
return *this;
}
int main(){
C c1(1);
C c2(2);
c1 = c2; // well-defined
c1.f();
}
In fact my observation is that it works with all major compilers but that makes it not legal...

Is the heap-allocated object of a class alive after its scope but before calling its destructor in C++

EDITED: Let's say we don't call explicitely the destructor of a heap-based object (delete A). If the pointer that points to "A" goes out-of-scope, is there a way the dynamic object remain accessible? for e.g., in the following code, can "a" be still alive after if-closing }?
class A{
void itsmethod();
};
int main()
{
if (true){
A* a = new A;
}
//...here how can I use dynamically allocated object?
a->itsmethod();
}
EDIT: As it was responded, the simplest immediate way is defining the pointer outside of if statement, but I am just wondering if there is any other option to prolong lifetime of dynamic object? Accordingly what else "A" class should provide? For instance passing by reference? Or equipping the class with move constructor... These suggestions may be irrelevant, I would like to hear your feedback.
I wonder if the object "a" is still alive after if-closing }?
The object a, which is a pointer, is not alive after the closing } of the if statement. The object to which a points to is in memory but it is not accessible with the posted code.
To be able to access the object to which a points to, declare a before the if statement.
int main()
{
A* a = nullptr;
if (true)
{
a = new A;
}
if ( a != nullptr )
{
a->itsmethod();
}
}
No and Yes: yes because dynamic memory is not freed up automatically. No because the code doesn't compile because a is scoped to if block and you are trying to use it from outside.
class A{
public:
int x;
};
int main(){
A* ptrA = NULL;
if(true){
// Everything declared here is accessible only here whatever being dynamic or static.
ptrA = new A;
ptrA->x = 10;
int x;
}
if(ptrA){
std::cout << ptrA->x << std::endl; // 10
delete ptrA;
}
return 0;
}
You must free up memory always when you're done with it otherwise it is a memory leak.
Above x is declared inside the if block on the stack so when end of if block is reached x will be destructed.
The object created by the new expression (i.e. by new A) will continue to exist.
The pointer a itself, since it has passed out of scope, will cease to exist as far as your program is concerned.
The net effect is that the dynamically allocated object is "leaked". It continues to exist after the block but there is no pointer or reference to it.
If you do something like
int main()
{
A *b;
if (true)
{
A* a = new A;
b = a;
}
a->itsmethod(); // diagnosible error
b->itsmethod(); // will work correctly
delete b; // destroy dynamically allocated object
b->itsmethod(); // undefined behaviour
}
then a->itsmethod() will give a compiler diagnostic (since a no longer exists) but the first b->itsmethod() will use the object created by the new expression. The second b->itsmethod() will compile, but yield undefined behaviour, since it accesses an object that no longer exists (due to the preceding delete b).
This happens because the pointer b continues to exist and, within the enclosed block, is assigned the value from a. So it then contains the result of the new expression.
No. The object 'a' will not be accessible anymore since its scope belongs to the if statement. However, there still is a memory address containing that object. This is why its good to do 'garbage collection' in programming.
Let's consider this demonstrative program
#include <iostream>
struct A
{
const char *s;
std::ostream & operator ()( std::ostream &os = std::cout ) const
{
return os << s;
}
};
int main()
{
A *a1;
if ( true )
{
A *a2 = new A { "Hello, Sepideha" };
a1 = a2;
}
( *a1 )() << std::endl;
delete a1;
return 0;
}
Its output is
Hello, Sepideha
Here the object a1 that has the type A * has the outer-most block scope of the function main.
The object a2 has the block scope of the if statement. It is alive only within this block.
At the same time there is dynamically created unnamed object of the type A pointer to which is assigned to a2 and then to a1. This unnamed object will be alive until the operator delete for a pointer that points to the object will be called. That is its live-time does not depend on the block scope of the if statement.
Because the pointer a1 points to this unnamed object then the pointer can be used outside the if statement to access the unnamed object in the dynamic memory.
After the statement with the delete operator this unnamed object stops to exist. But the object a1 is still alive.

How to keep the dynamic type of an object allocated on the stack?

Suppose I have:
class A { };
class B : public A { };
A f() {
if (Sunday())
return A;
else
return B;
}
Obviously this doesn't work since A's copy constructor would be called. Is there anyway to return stack allocated object without losing it's type?
I've tried using std::shared_ptr<A> but it got me into another issue since std::shared_ptr<B> isn't std::shared_ptr<A>.
It is not immediately possible to return a stack-allocated (i.e. local) object out of the function that created that object. Local objects are destroyed on function return. You can hide/obfuscate the actual nature of the object's allocation by using various "smart pointers" and similar techniques, but the object itself should be allocated dynamically.
Other that that, as long as the local object lifetime rules are obeyed, polymorphism for local objects works in exactly the same way as it works for any other objects. Just use a pointer or a reference
A a;
B b;
A *p = Sunday() ? &a : &b;
// Here `*p` is a polymorphic object
Pointer p in the above example remains valid as long as the local object lives, which means that you cannot return p from a function.
Also, as you see in the example above, it unconditionally creates both objects in advance, and then chooses one of the two while leaving the second one unused. This is not very elegant. You cannot create different versions of such object in different branches of if statement for the very same reasons for which you cannot return a local object from a function polymorphically: once the local block that created the object is complete, the object is destroyed.
The latter problem can be worked around by using a raw buffer and manual in-place construction
alignas(A) alignas(B) char object_buffer[1024];
// Assume it's big enough for A and B
A *p = Sunday() ? new(buffer) A() : new (buffer) B();
// Here `*p` is a polymorphic object
p->~A(); // Virtual destructor is required here
but it does not look pretty. A similar technique (involving copying of the buffer) can probably be used to make local polymorphic objects survive block boundaries (see #Dietmar Kühl's answer).
So, again, if you want to create only one object of the two and have your object to survive block boundaries, then immediate solutions put local objects are out of the question. You will have to use dynamically allocated objects.
It's not possible because of slicing. Use std::unique_ptr instead. You won't lose the dynamic type, but it will be accessible only through the interface of A.
The easiest approach is certainly to use a suitable smart pointer, e.g., std::unique_ptr<A>, as the return type and to allocate the object on the heap:
std::unique_ptr<A> f() {
return std::unique_ptr<A>(Sunday()? new B: new A);
}
For the approach returning a std::unique_ptr<A> which may point to a B, it is necessary that A has a virtual destructor as otherwise the code may result in undefined behavior when the std::unique_ptr<A> actually points to a B object. If A doesn't have a virtual destructor and can't be changed, the problem can be avoided by using a suitable std::shared_ptr<...> or by using a suitable deleter with the std::unique_ptr<...>:
std::unique_ptr<A, void(*)(A*)> f() {
if (Sunday()) {
return std::unique_ptr<A, void(*)(A*)>(new B, [](A* ptr){ delete static_cast<B*>(ptr); });
}
else {
return std::unique_ptr<A, void(*)(A*)>(new A, [](A* ptr){ delete ptr; });
}
}
If you don't want to allocate the objects on the heap, you can use a holder type which stores a union with A and B which is then appropriately constructed and destructed (the code below assumes that the copy of A or B won't throw an exception; if necessary, suitable move construction and move assignment can be added):
class holder {
bool is_b;
union {
A a;
B b;
} element;
public:
holder(): is_b(Sunday()) {
if (this->is_b) {
new(&this->element.b) B();
}
else {
new(&this->element.a) A();
}
}
holder(holder const& other) { this->copy(other); }
void copy(holder const& other) {
this->is_b = other.is_b;
if (this->is_b) {
new(&this->element.b) B(other.element.b);
}
else {
new(&this->element.a) A(other.element.a);
}
}
~holder() { this->destroy(); }
void destroy() {
if (this->is_b) {
this->element.b.~B();
}
else {
this->element.a.~A();
}
}
holder& operator= (holder const& other) {
this->destroy();
this->copy(other);
return *this;
}
operator A const&() const { return this->is_b? this->element.b: this->element.a; }
operator A&() { return this->is_b? this->element.b: this->element.a; }
};

Overloading assignment operator in polymorphic classes

I'm coming from java so please bear with me. I've read several other articles and can't seem to find an answer.
I've got a base class (Obj) header file shown below.
class Obj {
public:
Obj();
Obj(int);
int testInt;
virtual bool worked();
Obj & operator = (const Obj & other) {
if(this != &other) {
//other.testInt = this->testInt;
return *this;
}
}
};
Base class
Obj::Obj() {
}
Obj::Obj(int test) {
this->testInt = test;
}
bool Obj::worked() {
return false;
}
Here's the child class header
class Obj1 : public Obj {
public:
Obj1();
Obj1(int);
virtual bool worked();
};
Child class
#include "Obj1.h"
Obj1::Obj1() {
}
Obj1::Obj1(int a) {
this->testInt = a / 2;
}
bool Obj1::worked() {
return true;
}
Here's my main class
int main() {
Obj obj = Obj(99);
Obj1 obj1 = Obj1(45);
obj = obj1;
if(obj.worked())
cout << "good" << obj.testInt << endl;
else cout << "bad " << obj.testInt << endl;
if(obj1.worked()) {
cout << "1good " << obj1.testInt << endl;
} else
cout << "1bad " << obj1.testInt << endl;
return 0;
}
Here's the output when it's ran
bad 99
1good 22
How do I get it so obj = obj1; (found in main above) makes it so that obj.worked() will return true (since that's how obj1's class defines it)? Essentially how do I get it to behave like it would in java? I don't need a deep copy, I just want to toss out what obj used to reference and have it point to obj1 (I think thats how it works in java).
Note: I'm not very familiar with Java.
There's a major difference between "variables" in C++ and Java:
class X { public: int m = 5; };
X a; // no `= X();` required
X b;
a = b;
a.m = 42;
print(b.m); // this line is pseudo-code
In Java, variables may point to different objects. In the example above, after the assignment, a and b point to the same object. Modifying this object through one will make the modification visible when accessing the object through the other, print(b.m) will print 42.
In C++, "variables" (actually: names) always refer to the same object. There are two objects, one named a and one named b, and the assignment doesn't change that. Per default/convention, assignment in C++ means (deep) copy. a = b will be interpreted by most people and in the case of built-in types as copy the contents of b to a (or, more formally, change a such that it will be equal to b afterwards, without altering b).
Now it should be clear that you cannot alter which override of worked will be called by using the assignment in C++: which override of a virtual function is called is selected based on the type of the object (dynamic type), and you cannot change which object a name (variable) refers to.
However, there are pointers in C++, so-called raw pointers and smart pointers. Pointers are objects themselves that point to other objects of one specific type. X* is a raw pointer that points to an object of type X even with polymorphism! Similarly, std::shared_ptr<X> is a smart pointer that points to an object of type X.
std::shared_ptr<X> pa = std::make_shared<X>();
std::shared_ptr<X> pb = std::make_shared<X>();
Every make_shared creates an object. So we have four objects in this example: pa, pb, and the two unnamed objects created via make_shared.
For pointers, there are several operators for dealing with the object pointed to. The most important one is the asterisk, which dereferences the pointer. *pa will give you the object pa points to. The pa-> operator is a shorthand for (*pa)., so you can use it to access members of the object pointed to.
The assignment of pointers does not copy the object pointed to. After the assigment pa = pb, both will point to the same object. For smart pointers, that implies cleaning up objects that are not referred to any more:
std::shared_ptr<X> pa = std::make_shared<X>();
std::shared_ptr<X> pb = std::make_shared<X>();
// 4 objects exist at this point
pa = pb;
// only 3 objects still exist, the one `pa` formerly pointed to was destroyed
Polymorphism in C++ now works with either references (not explained here) or pointers. I said earlier that pointers can only point to one specific type of object. The crux is that this object might be part of a bigger object, e.g. via composition. But inheritance in C++ is very similar to composition: all the members of a base class become part of the base class subobject of a derived class' object:
std::shared_ptr<Obj1> pobj1 = std::make_shared<Obj1>();
std::shared_ptr<Obj> pobj = pobj1;
Here, pobj points to the Obj base class subobject within the object *pobj1 (i.e. within the object pobj1 points to).
Polymorphism now works via virtual functions. Those have a special rule for which function is actually called. The expression *pobj gives us the object which pobj points to, and it is of type Obj. But in this example, it is only a base class subobject, i.e. the object we originally created is of a type derived from Obj. For these cases, we differentiate between the static and the dynamic type of an expression:
The static type of *pobj is always Obj - generally, for an object p, whose type is pointer to some_type, the static type of *p is just some_type, removing one level of indirection / one pointer to.
The dynamic type of *pobj depends on which object pobj currently points to, and therefore generally is not known at compile-time. If the object is a base class subobject, we use the derived class object which it is part of, and recurse until the object we have is not a base class subobject any more. The type of the object we end up with is the dynamic type of the expression. In the example above, pobj points to the Obj base class subobject of *pobj1. The object *pobj1 itself is not a base class subobject here, therefore the dynamic type of *pobj is Obj1.
This dynamic type is now used to select which virtual function override is called. In the case pobj->worked(), where the dynamic type of *pobj is Obj1, the override selected is Obj1::worked, which will return true.
N.B. As Ben Voigt pointed out, the dynamic type does not depend on composition. It is only about inheritance.
In C++, your objects are values not references as in java. The assignment (obj = obj1) will reference to the Obj part of Obj1. In C++ you have to use pointer or reference.
Pointer
Obj* obj = new Obj(99);
Obj1* obj1 = new Obj1(45);
delete obj;// you have to free the memory manually as there's no GC in C++
obj = obj1;
obj->Worked();// the worked will be true here
delete obj1; // manually delete it
and if you want to delete obj1 via obj (delete obj instead of delete obj1), you have to change the Obj's destructor to be virtual, otherwise the destructor of Obj1 won't be called. Damn, this is C++, enjoy it.
reference
Obj obj = Obj(99);
Obj1 obj1 = Obj1(45);
Obj& obj2 = obj1;
obj2.Worked() // should be true
In this case, unlike the pointer, you don't have to delete the objects as they are on stack (not created by 'new'). But you cannot create an array of Obj& (e.g. vector)

C++: Difference between using the new keyword vs not when instantiating class members?

For a programming assignment, we are given a template class with two members declared not as pointers, but actual objects:
Foo member;
In the constructor, I tried member = *(new Foo()); initially, but learned that, at least sometimes, it was copying the new Foo object, and therefore causing memory leaks.
I finally discovered member = Foo(), and then looked up what the difference was. I learned that member will be allocated on the stack instead of the heap, and that it will be deleted once it is out of scope. How does this work for objects, though?
Is member only deleted when the parent / class object is deleted?
I also have another question about member = *(new Foo());. I was initializing two member variables of the same type:
// Members
Foo member1;
Foo member2;
// Constructor {
member1 = *(new Foo());
member2 = *(new Foo());
}
For some reason it seemed member1 was not being copied and it retained the same address as the initial Foo (i.e. there was no memory leak when it was deleted). member2 however, would be copied and had a different address, and memory was leaked. Is there an explanation for this?
Your analysis is incorrect. Both of these are memory leaks. What you are doing is allocating a new copy of the object, assigning the value to the member, and then discarding the pointer to the allocated memory without freeing that memory. It is a memory leak in both cases.
Now, consider the following code:
class MemberType {
public:
MemberType() { std::cout << "Default constructor" << std::endl; }
MemberType(int) { std::cout << "Int constructor" << std::endl; }
};
class Example1 {
public:
Example1() {}
private:
MemberType member_;
};
class Example2 {
public:
Example2() : member_(5) {}
private:
MemberType member_;
};
int main(int argc, char** argv) {
Example1 example1;
Example2 example2;
return 0;
}
This code will print both different types of constructors. Note that it did not take any initialization code at all for the member to be initialized in the default manner. Hence your new statement (or even an assignment without new) would be unnecessary in the default initialization case. When initializing members using a constructor other than the default constructor, the proper way to do this is with an initializer list. (The initializer list is what is happening with ": member_(5)" in the example.
Please see the C++ FAQ on constructors for more information about constructing objects in C++.
member = *(new Foo());
new Foo() dynamically allocates a Foo object and returns a pointer to that object. The * dereferences that pointer, giving you the Foo object. This object is then assigned to member, which involves calling the Foo copy assignment operator. By default, this operator assigns the values of each of the members of the right-hand side (the *(new Foo())) object into the left-hand side object (the member).
The problem is this: new Foo() dynamically allocates a Foo object and that object is not destroyed until you delete the pointer returned from the new. You don't save that pointer anywhere, so you've leaked the dynamically allocated object.
This is not the correct way to initialize an object.
member = Foo();
This creates a temporary, initialized Foo object and this object is assigned to member. At the end of this statement (at the ;, effectively), the temporary object is destroyed. member is not destroyed, and the contents of the temporary Foo object were copied into member, so this is exactly what you want to do.
Note that the preferred way to initialize member variables is using the initializer list:
struct C {
Foo member1, member2;
C() : member1(), member2() { }
};