clang - shared_ptr не может запустить свое средство удаления - PullRequest
0 голосов
/ 05 октября 2018

Этот код печатает 0 (без оптимизации) или 666 (с включенной оптимизацией) при построении с clang++ -std=c++11 (-O3 дает 666, что я и ожидал).Когда лямбда передается по универсальной ссылке, проблема исчезает.

К вашему сведению, 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

1 Ответ

0 голосов
/ 05 октября 2018

Ваш код имеет неопределенное поведение.Вы захватываете 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;
}
...