Deleting this pointer from constructor [duplicate] - c++

This question already has answers here:
c++ delete pointer issue, can still access data [closed]
(6 answers)
Closed 3 years ago.
I tried deleting this pointer from constructor, and afterwards when i access private variable through a member function, the variable is fetched correctly.
If I try to delete this again(in constructor or func()), my program crashes. That means this pointer is deleted fine in constructor.
class B
{
int a;
public:
B()
{
std::cout << this;
std::cout << "\nConstructor\n";
delete this;
a = 5;
std::cout << "\n" << this;
}
~B()
{
std::cout << "Destructor\n";
}
void func()
{
std::cout << "\n" << a << " Func\n";
}
};
int main(int argc, char* argv[])
{
B *b = new B();
b->func();
return 0;
}
But calling func() prints correct output. I expected some error due to deleted this. Why the implicit argument of func() is not updated when deleted?

delete this is allowed and just fine. Accessing any members of the class after deleting it however is not allowed and is undefined behavior. Your code appearing to work is one form that UB can take.

Related

Why doesn't accessing this nullpointer cause an exception? [duplicate]

This question already has answers here:
Accessing class members on a NULL pointer
(8 answers)
Closed 10 months ago.
#include <iostream>
class TestClass {
public:
TestClass() {
std::cout << "TestClass instantiated\n";
}
~TestClass() {
std::cout << "TestClass destructed\n";
}
void PrintSomething() {
std::cout << "TestClass is printing something\n";
}
};
int main() {
TestClass* tClass = new TestClass();
delete tClass;
tClass = nullptr;
tClass->PrintSomething();
std::cout << "Exiting...\n";
return 0;
}
Result:
TestClass instantiated
TestClass destructed
TestClass is printing something
Exiting...
I thought that trying to print something after the tClass pointer had been set to nullptr would cause a nullpointer exception error, but it prints just fine.
Why doesn't accessing this nullpointer cause an exception?
Because it's not specified to cause an exception. Accessing through a null poitner results in undefined behaviour. Don't do it.

Deleting a pointer twice in C++ [duplicate]

This question already has answers here:
What is The Rule of Three?
(8 answers)
How to actually implement the rule of five?
(6 answers)
Closed 1 year ago.
I am new to code in C++. So, below code looks pretty decent to me.
#include<iostream>
using namespace std;
class B {};
class A {
public:
B* b;
A() {
cout << "ctor" << endl;
b = new B();
}
~A() {
cout << "dtor" << endl;
delete b;
}
};
void func(A a) {
cout << a.b << endl;
}
int main() {
A a;
cout << a.b << endl;
func(a);
cout << a.b << endl;
}
But I found an issue with this code. When I run this, it gives free(): double free detected in tcache 2 error. I know the cause of this error (it is because dtor is being called 2 times).
One way to solve the problem is, writing a copy constructor for class A where, I create a new B() like this.
A(A const& a) {
cout << "copy ctor" << endl;
b = new B();
*b = *a.b;
}
But if B is a very big class, and hence if I prefer to share b pointer, then how would I avoid this problem?

How does shared_ptr work in c++ without initialization [duplicate]

This question already has answers here:
What will happen when I call a member function on a NULL object pointer? [duplicate]
(6 answers)
Closed 3 years ago.
I was going through shared_ptr and came across this.
class A
{
public:
A() { cout << "In constructor" << endl; }
~A() { cout << "Destructor" << endl; }
void fun() { cout << "In fun... " << endl; }
};
int main()
{
shared_ptr<A> a;
a->fun();
return 0;
}
The output of this is - In fun...
I would like to understand how is this giving above output.
On further experimentation if there is a member variable and being used in this function it throws an SIGSEGV.
class A
{
public:
A() { cout << "In constructor" << endl; }
~A() { cout << "Destructor" << endl; }
void fun() { a = 5 ; cout << "In fun... " << endl; }
int a;
};
int main()
{
// A::fun();
shared_ptr<A> a;
a->fun();
return 0;
}
Above throws SIGSEGV stating this pointer is null.
The code in both cases has undefined behavior because the raw pointer of the shared_ptr pointer is initialized by nullptr.
In the second case the code tried to access memory of the data member a using nullptr.
In the first case the code executed without a failure only due to there is no access to the memory of the object. However the code has undefined behavior because you may not use a null-pointer to access non-static members of a class..

Placement new on this pointer [duplicate]

This question already has an answer here:
Placement new and assignment of class with const member
(1 answer)
Closed 4 years ago.
The 2 print statements print different numbers. As far as I can see I'm not doing any dodgy const_cast here so I'm not sure what UB I could have possibly committed.
Is this code well-formed?
Can the compiler rely on the fact that A::num is const so it's allowed to print the same number ?
Code:
struct A
{
const int num = 100;
A() {}
A(int in) : num{in} {}
void call()
{
new (this) A{69};
}
};
int main()
{
A a;
std::cout << a.num << '\n';
a.call();
std::cout << a.num << '\n';
}
No, your code has UB. Remove the const on num and you don't get any UB anymore.
The problem is that the standard provides a guarantee that a const object doesn't change. But if you reuse the same storage, then you can "modify" the const object in a way.
[basic.life]p8 explicitly prohibits this by saying that the old name of the object only refers to the new object under certain conditions. One of them is that your class doesn't have any const members. So by extension, your second a.num is UB, as the a refers to the old destructed object.
However, there are two ways to avoid this UB. First, you can store the pointer to the new object:
struct A *new_ptr;
struct A {
// [...]
void call() {
new_ptr = new (this) A{69};
}
};
int main()
{
A a;
std::cout << a.num << '\n';
a.call();
std::cout << new_ptr->num << '\n'; // ok
}
Or use std::launder:
std::cout << std::launder(&a)->num << '\n'; // second access

Trying to create object using constructor inside static function in C++

I was trying to create an object inside static function using a constructor.
Here is the code
class A {
public:
A() { this->a = 50; std::cout << "constructor called... " << this << std::endl; setAddr(this); }
~A() { this->a = 10; std::cout << "destructor called... " << this << std::endl; }
int a;
static A* addr;
static void setAddr(A* ad) { addr = ad; }
static A &create() { A(); return *addr; }
};
A* A::addr = NULL;
int main() {
A &ptr = A::create();
std::cout << "a = " << ptr.a << std::endl;
ptr.a = 100;
std::cout << "a = " << ptr.a << std::endl;
getch();
return 0;
}
I know using new is best way to do it,but i was trying to do it using contructor to know whether it can be done or not.
The output was:
constructor called... 009AF874
destructor called... 009AF874
a = 10
a = 100
Now here is my question,
1) why destructor is called when did not create an object using any declaration like A obj;
2) and if the destructor is called then how I am able to assign a value to otr.a;
By looking at the program's output I made the following conclusion.
1) I read somewhere that constructor is called after the memory has been allocated to object. And if an object is created then it has to be destroyed and the scope of the obj decided to destroy it now.
2) Since object address has previous values before destroying it and returns call return the address of the variable storing it. When I try to access it, I was able to do so because that memory address still exists.
That's not how you make a singleton. The statement
A();
creates a temporal object of class A that is destroyed (as per standard) at end of statement.
Indeed, memory is allocated before call of constructor. Resulting object can be assigned or passed by reference or value to any function of this statement, but in former case, reference is valid only until end of call expression. Exception is that if it was assigned to reference, its length of life is extended to one
of reference. After life of object ended, any access to memory it used results in UB, provided that it could be used by any other operations.
Any access to object after destructor was called is an UB as well.
Here is an example (this code intentionally contains UB)
#include <iostream>
class A {
public:
A() { this->a = 50; std::cout << "constructor called... " << this << std::endl; }
~A() { this->a = 10; std::cout << "destructor called... " << this << std::endl; }
int a;
static const A &create() {
const A& addr = A();
std::cout << "a = " << addr.a << std::endl;
return addr;
}
};
int main() {
const A &ref = A::create();
std::cout << "a = " << ref.a << std::endl;
return 0;
}
Note, that C++ allows to bind temporary only to const reference. There are way to work around that, but that's irrelevant.
Output of this program may vary, depending on compiler and level of optimization. E.g. clang with no optimization:
constructor called... 0x7ffc1f7991d0
a = 50
destructor called... 0x7ffc1f7991d0
a = 4202884
gcc may output 10 in last line. MS may crash on it. Keyword is "may", there is no rule that governs what would happen. Object stopped existing after create() returned reference to it because lifespan of addr came to end, and we are left with dangling reference.
Obviously we can extend lifespan of addr by making it static.
static const A &create() {
static const A& addr = A();
std::cout << "a = " << addr.a << std::endl;
return addr;
}
Static variable in function's scope will be created at first call of function and stops to exist when process stops.
constructor called... 0x6031b8
a = 50
a = 50
destructor called... 0x6031b8