4

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();
};
motam79
  • 3,542
  • 5
  • 34
  • 60

2 Answers2

3

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
}
Gaxio
  • 121
  • 3
  • 2
    [Calling a method on a null pointer is still undefined behavior even if the method doesn't need any instance variables.](https://stackoverflow.com/questions/2533476/what-will-happen-when-i-call-a-member-function-on-a-null-object-pointer) It could segfault, or appear to work, or summon the [nasal demons](http://www.catb.org/jargon/html/N/nasal-demons.html). – user2357112 Jul 12 '18 at 05:32
  • Thanks, I've updated my answer to include that and softened my language (does not, instead of will not). – Gaxio Jul 12 '18 at 06:00
1

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.

Ben Jones
  • 652
  • 6
  • 21
  • "really invalid" isn't a useful expression. The other answer adds a lot more clarity to the specifics about why this code does or does not segfault. Stack overflow's audience wants specific, informational answer, not explanations you'd give to a non-technical reader. And "C++ does not guarantee a segfault..." - C++ doesn't not just guarantee that, it fundamentally has no concept of signals at all. – xaxxon Jul 12 '18 at 03:10