为啥这个悬空的 std::weak_ptr 不会导致 SEGFAULT? [复制]

Posted

技术标签:

【中文标题】为啥这个悬空的 std::weak_ptr 不会导致 SEGFAULT? [复制]【英文标题】:Why doesn't this dangling std::weak_ptr cause SEGFAULT? [duplicate]为什么这个悬空的 std::weak_ptr 不会导致 SEGFAULT? [复制] 【发布时间】:2018-12-20 02:59:53 【问题描述】:

在下面的代码中,我在作用域中创建了一个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();
;

【问题讨论】:

C++ 不保证无效代码会出现段错误。 取消引用 NULL 指针是 UB。由于foo的定义根本没有使用this,所以编译器会忽略它。 【参考方案1】:

你实际上并没有取消引用那里的任何东西。如果锁定的 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

【讨论】:

Calling a method on a null pointer is still undefined behavior even if the method doesn't need any instance variables. 它可能会出现段错误,或者看起来可以工作,或者调用nasal demons。 谢谢,我已经更新了我的答案以包含它并软化了我的语言(不,而不是不会)。【参考方案2】:

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

【讨论】:

“真的无效”不是一个有用的表达方式。另一个答案更加清楚地说明了此代码为什么会或不会出现段错误的细节。 Stack Overflow 的受众想要具体的、信息性的答案,而不是你会给非技术读者的解释。并且“C++ 不保证段错误......” - C++ 不只是保证,它根本没有信号的概念。

以上是关于为啥这个悬空的 std::weak_ptr 不会导致 SEGFAULT? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

组合逻辑电路中为啥TTL与非门电路的输入端悬空时,相当于高电平输入?

FPGA管脚悬空后状态为啥不稳定?

使用std智能指针的正确方法来确保ptr安全

什么是智能指针,什么时候应该使用?

为啥兀/2之类的角度的导函数为0?

C++智能指针