【问题标题】: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,所以编译器会忽略它。

标签: c++ weak-ptr


【解决方案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
}

【讨论】:

【解决方案2】:

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

【讨论】:

  • “真的无效”不是一个有用的表达方式。另一个答案更加清楚地说明了此代码为什么会或不会出现段错误的细节。 Stack Overflow 的受众想要具体的、信息性的答案,而不是你会给非技术读者的解释。并且“C++ 不保证段错误......” - C++ 不只是保证,它根本没有信号的概念。
猜你喜欢
  • 2021-12-18
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 1970-01-01
  • 2017-04-26
  • 1970-01-01
相关资源
最近更新 更多