【问题标题】:How to move non-copyable local variable out of lambda in C++?如何在 C++ 中将不可复制的局部变量移出 lambda?
【发布时间】:2016-04-30 23:40:18
【问题描述】:

我想实现一个简单的运行时检查宏,所以它的工作方式如下:

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;
}

但是no luck - 复制构造函数被删除了:

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

尝试 #2

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

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

嗯,还是no luck

尝试 #3

一个肯定行不通的绝望尝试:

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

它编译甚至runs,但是operator &lt;&lt;在析构函数之后被调用:

0xbfe84064 dtor
A
0xbfe84064 <<

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

【问题讨论】:

  • 我真的会避免从函数返回局部变量(包括 lambda 表达式)。在你的情况下 - 只是#define CHECK(e) if (!(e)) Log{} &lt;&lt; "A"。由于其他原因更好#define CHECK(e) if (e) {} else Log{} &lt;&lt; "A"
  • @PiotrNycz 这对我来说不是一个好的变体,因为我想打印堆栈跟踪以及用户提供的消息 - 这就是为什么我在 lambda 中使用 Log 来做一些事情。跨度>
  • 完全没有问题。您可以创建打印堆栈跟踪的对象 - 例如Log{} &lt;&lt; stackTracePrinter。或者你可以在一些 Log 专业化构造函数中做你能想象的一切......

标签: c++ c++11 lambda move-semantics


【解决方案1】:

使移动构造函数default,即

Log(Log&&) = default;

因为否则存在用户提供的复制ctor(即使deleted)disables the move ctor。您还应该return log; 而不是return move(log);,因为将调用默认移动ctor(因为删除了复制ctor)。参见例如this 详细了解为什么通常应避免使用 return move

Live on Coliru

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    • 2020-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    相关资源
    最近更新 更多