首页 > 解决方案 > clang - shared_ptr 无法运行其删除程序

问题描述

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

仅供参考,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++11lambdaclangshared-ptr

解决方案


您的代码具有未定义的行为。f您通过引用捕获,onScopeExit但是一旦您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;
}

推荐阅读