10

我的代码:

#include <iostream>
#include <functional>
using namespace std;

struct A {
  A() = default;
  A(const A&) {
    cout << "copied A" << endl;
  }
};

void foo(A a) {}

int main(int argc, const char * argv[]) {
  std::function<void(A)> f = &foo;
  A a;
  f(a);
  return 0;
}

我在控制台上看到两次“复制的 A”。为什么对象被复制两次,而不是一次?我怎样才能正确防止这种情况?

4

2 回答 2

10

std::function<R(Args...)>化有一个调用操作符,声明如下:

R operator()(Args...) const;

在您的情况下,这意味着操作员需要A. 因此,f(a)由于按值传递语义,调用会产生副本。但是,底层foo目标也按值接受其参数。f因此,当参数 to被转发到时,将会有第二个副本foo

这是设计使然,事实上,如果A有一个移动构造函数,那么只有一个副本后面跟着一个移动构造——调用f(std::move(a))只会导致两个移动构造。如果您觉得两个副本太多,您需要重新考虑是否应该同时使用fooand来代替 eg ,和/或是否可以有一个合理的 move 构造函数。fAA const&A

您也可以std::function<void(A const&)> f = &foo;不修改foo. 但是您应该保留它,以防修改foo超出您的控制范围,和/或使A廉价移动可构造不是一种选择。在 C++11 中按值传递没有错,所以我建议要么两者都应该采用A,要么都应该采用A const&

于 2012-08-10T15:33:29.937 回答
1

它被复制是因为您按值传递它。您可以通过将其作为 const 引用传递来避免所有副本。

于 2012-08-10T15:17:20.653 回答