【问题标题】:clang - shared_ptr fails to run its deleterclang - shared_ptr 无法运行其删除程序
【发布时间】:2019-03-11 02:29:57
【问题描述】:

当使用clang++ -std=c++11 构建时,此代码将打印0(没有优化)或666(启用优化)(-O3 产生666,这是我所期望的)。当 lambda 通过通用引用传递时,问题就消失了。

仅供参考,GCC 在我测试过的所有版本上打印 666

是编译器错误还是代码不正确?

#include <memory>
#include <iostream>

template <typename T>
std::shared_ptr<void> onScopeExit(T f)
{
    return std::shared_ptr<void>((void*)1, [&](void *) {
        f();
    });
}

struct A {
  void f() {
    auto scopeGuard = onScopeExit([&]() { i = 666; }); //  [1]
    // ... (some work)
  } // (lambda [1] being ? called on scope exit)

  int i = 0;
};

A a;

int main() {
  a.f();
  std::cout << a.i << std::endl;
}

有问题的编译器是:

Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.7.0

【问题讨论】:

    标签: c++ c++11 lambda clang shared-ptr


    【解决方案1】:

    您的代码具有未定义的行为。您在onScopeExit 中通过引用捕获f,但是一旦您从函数返回shared_ptr,删除器现在持有对f 的悬空引用,因为f 超出了范围。你需要做的是通过值捕获f,然后你就没有悬空引用了

    template <typename T>
    std::shared_ptr<void> onScopeExit(T f)
    {
        return std::shared_ptr<void>((void*)1, [=](void *) {
            f();
        });
    }
    
    struct A {
      void f() {
        auto scopeGuard = onScopeExit([&]() { i = 666; }); //  [1]
        // ... (some work)
      } // (lambda [1] being ? called on scope exit)
    
      int i = 0;
    };
    
    A a;
    
    int main() {
      a.f();
      std::cout << a.i << std::endl;
    }
    

    【讨论】:

    • 谢谢!只是一个额外的小问题:如果我将f 通过T&amp;&amp;std::forward 传递给 lambda 是否也可以? (或者可能更好?)
    • @puhacz 应该没问题。您也可以将函数保留在答案中,并将[=] 替换为[f = std::move(f)],以便将f 移动到lambda 中。当您将左值传递给onScopeExit 时,这只是您想要发生的事情的问题。你复制它,还是你持有它的引用。仅当您将 scopeGuard 返回超出范围时,引用才会很糟糕。
    猜你喜欢
    • 2019-02-12
    • 2014-03-28
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 2012-06-07
    • 2013-02-10
    • 1970-01-01
    相关资源
    最近更新 更多