为什么这个悬空的std :: weak_ptr不会导致SEGFAULT?

时间:2018-07-12 01:27:57

标签: c++ weak-ptr

在下面的代码中,我在范围内创建一个shared_ptr并将其分配给weak_ptr。为什么在运行代码时我没有得到SEGFAULT,这是怎么回事,因为wp应该在范围外无效,对吧?

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();
};

2 个答案:

答案 0 :(得分:3)

您实际上并没有取消引用任何内容。如果锁定的shared_ptr为null,则lock方法仍将返回shared_ptr,但该shared_ptr也将为null。在此示例中,foo不会在我的编译器上崩溃,因为它从未取消引用空指针,但是它是未定义的行为,因此您永远不知道会发生什么。但是,bar总是会崩溃,因为它需要取消引用指针才能到达x。

之所以起作用,是因为所有成员函数都编译为普通函数,这些普通函数将指向该对象的指针作为第一个参数,从该函数体以 this 进行访问。如果函数主体中没有任何东西取消引用 this ,则在大多数情况下在nullptr上调用此函数可能会起作用。不过,您不应该这样做,因为将来的编译器更改或移植到另一个体系结构的端口都可能导致崩溃。

#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
}

答案 1 :(得分:1)

通常,除非您对无效的内存进行了某些操作,否则您将不会遇到段错误(然后它就不会总是发生段错误-由硬件向操作系统发送信号,然后由操作系统决定)。操作系统实际上会使程序崩溃)。如果您要在x中设置foo,则您更有可能看到段错误-但正如user2357112指出的那样,c ++标准不能保证对无效代码进行段错误。