如何在 C++ 中将不可复制的局部变量移出 lambda

How to move non-copyable local variable out of lambda in C++?

本文关键字:可复制 局部变量 移出 lambda C++      更新时间:2023-10-16

我想实现一个简单的运行时检查宏,所以它的工作原理是:

CHECK(expr) << "Some problem!";

为此,我编写了一个简化的日志记录类:

class Log {
 public:
  Log() = default;
  Log(const Log&) = delete;
  ~Log() {
    cout << this << " dtor" << endl;
    cout << stream_.str() << endl;
  }
  template <class T>
  Log& operator<<(const T& info) {
    cout << this << " <<" << endl;
    stream_ << info;
    return *this;
  }
 private:
  stringstream stream_;
};

并让宏是:

#define CHECK(expr) 
  if (!(expr)) [] { /* See attempts below */ }()

现在让我们尝试实现 lambda。


尝试 #1

最简单的方法应该是:

[] {
  Log log;
  log << "A";
  return log;
}

但是没有运气 - 复制构造函数被删除:

error: use of deleted function 'Log::Log(const Log&)'

尝试 #2

好的,让我们显式移动局部变量:

[] {
  Log log;
  log << "A";
  return move(log);
}

嗯,还是没有运气。

尝试 #3

一个绝望的尝试,当然不应该奏效:

[]() -> Log&& {
  Log log;
  log << "A";
  return move(log);
}

它编译甚至运行,但 operator << 是在析构函数之后调用的:

0xbfe84064 dtor
A
0xbfe84064 <<

帮助我弄清楚从 lambda 返回变量做错了什么?

使移动构造函数default,即

Log(Log&&) = default;

因为否则,用户提供的副本 CTOR 的存在(即使 delete d)会禁用移动 CTOR。您还应该return log;而不是return move(log);,因为将调用默认的移动 ctor(因为复制 ctor 被删除)。例如,有关为什么通常应避免return move的更多详细信息,请参阅此内容。

住在科里鲁