This question already has answers here:
When does invoking a member function on a null instance result in undefined behavior?
(2 answers)
Closed 4 years ago.
In the following code I create a shared_ptr in the scope and assign it to a weak_ptr. How come when running the code I don't get SEGFAULT, because wp should be invalid out of scope, right?
namespace {
struct Dummy {
int x;
void foo() {
std::cout << "dummy created\n";
}
~Dummy()
{
std::cout << "dummy destroyed\n";
}
};
}
TEST(experimental, ptr_test){
std::weak_ptr<Dummy> wp;
{
auto sp = std::make_shared<Dummy>();
wp = sp;
}
wp.lock()->foo();
};
You're not actually dereferencing anything there though. The lock method will still return a shared_ptr if the locked shared_ptr is null, but that shared_ptr will also be null. In this example, foo doesn't crash on my compiler since it never dereferences the null pointer but it's undefined behavior so you never know what will happen. However, bar will always crash since it needs to dereference the pointer in order to get to x.
The reason why this happens to work is that all member functions compile to normal functions that take a pointer to the object as their first parameter accessible from the function body as this. Calling this function on nullptr will probably work most of the time if nothing in the body of the function dereferences this. You shouldn't do it though, future compiler changes or a port to another architecture could cause this to crash.
#include <iostream>
#include <memory>
struct Dummy {
int x;
Dummy()
: x(10) {
std::cout << "Dummy created" << std::endl;
}
~Dummy() {
std::cout << "Dummy destroyed" << std::endl;
}
void foo() {
std::cout << "foo" << std::endl;
}
void bar() {
std::cout << x << std::endl;
}
};
int main() {
std::weak_ptr<Dummy> wp;
{
auto sp = std::make_shared<Dummy>();
wp = sp;
}
auto locked = wp.lock();
if(locked.get() == nullptr) {
std::cout << "Locked pointer is null" << std::endl;
}
locked->foo(); // Does not crash
((Dummy*)nullptr)->foo(); // Does not crash
locked->bar(); // Will crash
}
Generally, you won't get a segfault unless you actually do something with the invalid memory (and then it won't always segfault - it is up to the hardware to send a signal to the OS, and then up to the OS to actually crash the program). If you were to set x in foo, you may have a better chance of seeing a segfault - but as user2357112 pointed out, the c++ standard does not guarantee a segfault for invalid code.
Related
In my understanding that might be wrong, declaring a pointer to local object is dangerous or probably has no purpose.
The following globally defined function Factory that returns a pointer to a local object has no purpose. Right after invoking Factory(), the returned address is pointing to a local object that has been destroyed.
Foo* Factory()
{
// It is wrong to return the address of a local object!
// It is only for illustration!
Foo local{ 100 };
return &local;
}
Invoking Print() produces a garbage value. This is understandable so far.
Now consider the second case with a local scope as follows.
int main()
{
Foo* p ;
{
Foo local{ 100 };
p = &local;
}
p->Print();// 100 is printed even though p is pointing to a local scoped object that has been destroyed.
return 0;
}
What I don't understand is why I can still invoke Print() on the pointed object that should have been destroyed. Any comments are welcome!
Complete Example
#include <iostream>
class Foo
{
private:
int _data;
public:
Foo(int data) :_data{ data }
{
std::cout << "Ctor: " << this << std::endl;
}
~Foo()
{
std::cout << "Dtor: " << this << std::endl;
}
void Print()
{
std::cout << "Data: " << _data << std::endl;
}
};
Foo* Factory()
{
// It is wrong to return the address of a local object!
// It is only for illustration!
Foo local{ 100 };
return &local;
}
int main_1()
{
Foo* p = Factory();
p->Print();// Garbage gets printed because p is pointing to a local object that has been destroyed.
return 0;
}
int main_2()
{
Foo* p ;
{
Foo local{ 100 };
p = &local;
}
p->Print();// 100 is printed even though p is pointing to a local scoped object that has been destroyed.
return 0;
}
Undefined behavior
First I want to give you a brief explanation of undefined behavior. If you want to you can read more here Undefined behavior.
Undefinded behavior renders the entire program meaningless if certain rules of the language are violated. The compiler can basicly decide what to do. But like mentioned on cppreference: Compilers are not required to diagnose undefined behavior (although many simple situations are diagnosed), and the compiled program is not required to do anything meaningful. So in short there are no restrictions on the behavior of the program.
Your case
Both examples invoke undefned behavior:
int main_2()
{
Foo* p ;
{
Foo local{ 100 };
p = &local;
}
p->Print();
return 0;
}
int main_1()
{
Foo* p = Factory();
p->Print();
return 0;
}
So like we learned undefinded behavior is undefinded. So anything can happen. In the second case your compiler was probably smart enough to notice the issue.Because the behavior is undefined your program could also crash or do other weird things.
This question already has answers here:
Is it OK to reference an out-of-scope local variable within the same function?
(4 answers)
Closed 4 years ago.
sample1.cpp
#include <iostream>
int main()
{
int* aPtr = nullptr;
{
int a = 3;
aPtr = &a;
}
std::cout << *aPtr << std::endl;
return 0;
}
Output
3
I am able to access a through aPtr.
Does that mean a is not deallocated even after it goes out of
scope.
Does that mean a is deallocated only after the function in
which it is defined unwinds.
Or is this an undefined behavior that currently outputs some value?
sampe2.cpp
#include <iostream>
struct Box
{
Box(int a_)
:a(a_)
{}
int getValue() const { return a;}
~Box()
{
std::cout << "Destructor called" << std::endl;
}
private:
int a;
};
int main()
{
Box* boxPtr = nullptr;
{
Box box = 23;
boxPtr = &box;
}
std::cout << boxPtr->getValue() << std::endl;
return 0;
}
Output
Destructor called
23
I am able to access box through boxPtr even after destructor of box is called.
As mentioned in the comments, in both cases you are facing undefined behavior (so anything is allowed to happen). The stack variables are destroyed as soon as they go out of scope, the memory occupied by them is freed, although usually it's not immediately overwritten (at least in simple cases like above), therefore the pointer pointing at such variable, might sometimes exhibit more or less "valid" properties (as in it looks like the object is still valid), despite it clearly dangling.
This question already has answers here:
What will happen when I call a member function on a NULL object pointer? [duplicate]
(6 answers)
Closed 4 years ago.
I was trying some code. Mistakenly wrote below code (Luckily Now)
Snippet 1
#include<iostream>
using namespace std;
class A {
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void print() { cout << "A::print()=>" <<this<< endl; }
};
int main() {
A* a = new A;
a->print();
delete a;
a = NULL;
cout << a << endl;
a->print();
return 0;
}
As I know, since I have deleted "a", the program should have crashed (Not so true now). But it did not. Can some please explain the reason behind this. The output image is also attached.
But As soon as I include any member variable in the above program, it crashes.
How ? Why ? Please see Program 2.
Snippet 2
class A {
int val;
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void print() { cout << "A::print()=>" <<this << val << endl; }
};
int main() {
A* a = new A;
a->print();
delete a;
a = NULL;
cout << a << endl;
a->print();
return 0;
}
The Above program is crashing. Why not the 1st program?
PS: There are chances that it may be the duplicate question. I tried to find the question like this but couldn't find. Though I got this question, I feel it's not the same as I am looking for.
The first one doesn’t dereference any memory pointed by anything, therefore it might not crash. You’re only printing out this which is a pointer value and you’re not dereferencing it. Note that this doesn’t mean it’s ok and will always work! It is definitely not allowed and shouldn’t be done. What happens when this is done is undefined.
Your second example actually tries to use a member variable which means an attempt is made to access memory that isn’t valid. This is also undefined behavior and may cause a crash, or something else. It is undefined.
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 9 years ago.
First of all I'd like to understand why I get lines (5) and (6) in the output and not only one of them.
Second, why mc1.print() prints valid values? Shouldn't _ms point to undefined place after mc1(&MyStruct(mc2)) because the place where MyStruct was created (in cast operator) was already unwind?
struct MyStruct
{
int w;
int h;
MyStruct()
{
cout << "MyStruct" << endl;
}
~MyStruct()
{
cout << "~MyStruct: w=" << w << "h=" << h << endl;;
}
};
class MyClass1
{
public:
MyClass1(MyStruct* ms)
:_ms(ms)
{
cout << "MyClass1" << endl;;
}
~MyClass1()
{
cout << "~MyClass1" << endl;
}
void print()
{
cout << "print: w=" << _ms->w << "h=" << _ms->h << endl;
}
MyStruct* _ms;
};
class MyClass2
{
public:
MyClass2()
{
cout << "MyClass2" << endl;
}
~MyClass2()
{
cout << "~MyClass2" << endl;
}
operator MyStruct()
{
MyStruct ms;
ms.h = 11;
ms.w = 22;;
return ms;
}
};
int main()
{
MyClass2 mc2;
MyClass1 mc1(&MyStruct(mc2));
mc1.print();
return 0;
}
the output is
1. MyClass2
2. MyStruct
3. ~MyStruct: w=22h=11
4. MyClass1
5. ~MyStruct: w=22h=11
6. ~MyStruct: w=22h=11
7. print: w=22h=11
Why there is still valid access to struct after leaving the scope?
There isn't. It isn't valid. You can try to read arbitrary memory addresses, but doing so is not valid". The C++ standard just doesn't say what should happen if you do something "invalid". So your code is allowed to do what you're observing.
First of all I'd like to understand why I get lines (5) and (6) in the output and not only one of them.
I've no idea. I don't, but since the program has undefined behaviour, anything could happen in principle.
Second, why mc1.print() prints valid values?
It doesn't. It gives undefined behaviour, by printing whatever happens to be in the memory that was once occupied by the dead temporary, if that memory is still accessible. In your case, it just happens that nothing has reused or otherwise invalidated the memory, so you happen to see the values you put there when the temporary was alive.
Shouldn't _ms point to undefined place after mc1(&MyStruct(mc2)) because the place where MyStruct was created (in cast operator) was already unwind?
It points to some memory location which no longer contains a valid object. Typically, the stack frame isn't released until the function returns; and even when it is, the memory typically remains accessible. So accessing a dead object gives you some kind of undefined behaviour, which may not be whatever undefined behaviour you thought it should give.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++: Delete this?
Object-Oriented Suicide or delete this;
I wonder if the code below is run safely:
#include <iostream>
using namespace std;
class A
{
public:
A() {
cout << "Constructor" << endl;
}
~A() {
cout << "Destructor" << endl;
}
void deleteMe() {
delete this;
cout << "I was deleted" << endl;
}
};
int main()
{
A *a = new A();
a->deleteMe();
cout << "Exit ...";
return 0;
}
Output is:
Constructor
Destructor
I was deleted
Exit ...
and program exit normally, but are there some memory access violents here?
It's ok to delete this in case no one will use the object after that call. And in case the object was allocated on a heap of course
For example cocos2d-x game engine does so. It uses the same memory management scheme as Objective-C and here is a method of base object:
void CCObject::release(void)
{
CCAssert(m_uReference > 0, "reference count should greater than 0");
--m_uReference;
if (m_uReference == 0)
{
delete this;
}
}
I don't think it's a c++ way of managing memory, but it's possible
It's ok, because you have running simple method. After delete this, all variables and virtual table are clear. Just, analyze this example:
#include <iostream>
class foo
{
public:
int m_var;
foo() : m_var(1)
{
}
void deleteMe()
{
std::cout << m_var << "\n";
delete this;
std::cout << m_var << "\n"; // this may be crush program, but on my machine print "trash" value, 64362346 - for example
}
virtual void bar()
{
std::cout << "virtual bar()\n";
}
void anotherSimpleMethod()
{
std::cout << "anotherSimpleMethod\n";
}
void deleteMe2()
{
bar();
delete this;
anotherSimpleMethod();
// bar(); // if you uncomment this, program was crashed, because virtual table was deleted
}
};
int main()
{
foo * p = new foo();
p->deleteMe();
p = new foo();
p->deleteMe2();
return 0;
}
I've can't explain more details because it's need some knowledge about storing class and methods in RAM after program is loaded.
Absolutelly, you just run destructor. Methods does not belongs to object, so it runs ok. In external context object (*a) will be destroyed.
When in doubt whether theres strange things going on in terms of memory usage (or similar issues) rely on the proper analysis tools to assist you in clarifying the situation.
For example use valgrind or a similar program to check whether there are memory leaks or similar problems the compiler can hardly help you with.
While every tool has its limitations, oftentimes some valuable insights can be obtained by using it.
There is no memory access violation in it, you just need to be careful. But deleting this pointer is not recommended at all in any language, even though the code above would work fine. As it is same as delete a, But try doing it other way, the safe way.
For example there is something illogical in your posted code itself.
void deleteMe()
{
delete this;
cout << "I was deleted" << endl; // The statement here doesn't make any sense as you no longer require the service of object a after the delete operation
}
EDIT: For Sjoerd
Doing it this way make more sense
void deleteMe()
{
delete this;
}
int main()
{
A *a = new A();
a->deleteMe();
cout << "a was deleted" << endl;
cout << "Exit ...";
return 0;
}
The second line in your deleteMe() function should never be reached, but its getting invoked. Don't you think that its against the language's philosophy?