防止不必要的C++仿函数对象副本

Tim*_*ter 16 c++ optimization templates

我有一个类,它可以累积有关一组对象的信息,可以作为仿函数或输出迭代器.这允许我做以下事情:

std::vector<Foo> v;
Foo const x = std::for_each(v.begin(), v.end(), Joiner<Foo>());
Run Code Online (Sandbox Code Playgroud)

Foo const x = std::copy(v.begin(), v.end(), Joiner<Foo>());
Run Code Online (Sandbox Code Playgroud)

现在,理论上,编译器应该能够使用复制省略和返回值优化,以便只Joiner需要创建一个对象.然而,在实践中,该函数会生成一个操作副本,然后将其复制回结果,即使在完全优化的构建中也是如此.

如果我将仿函数创建为左值,则编译器会创建两个额外的副本而不是一个副本:

Joiner<Foo> joiner;
Foo const x = std::copy(v.begin(), v.end(), joiner);
Run Code Online (Sandbox Code Playgroud)

如果我笨拙地强制将模板类型强制转换为引用,它会传入引用,但无论如何都要复制它并返回对(现在已销毁的)临时副本的悬空引用:

x = std::copy<Container::const_iterator, Joiner<Foo>&>(...));
Run Code Online (Sandbox Code Playgroud)

我可以通过在样式的仿函数中使用对状态的引用而不是状态本身来使副本变得便宜std::inserter,从而导致类似这样的事情:

Foo output;
std::copy(v.begin(), v.end(), Joiner<Foo>(output));
Run Code Online (Sandbox Code Playgroud)

但是这使得不可能使用不可变对象的"功能"风格,而且通常不那么好.

有没有办法鼓励编译器忽略临时副本,或者让它一直通过引用并返回相同的引用?

Ter*_*fey 15

你偶然发现了一个经常抱怨行为的人<algorithm>.他们可以用仿函数做什么没有限制,所以问题的答案是否定的:没有办法鼓励编译器忽略副本.它不是(总是)编译器,它是库实现.他们只是喜欢按值传递仿函数(想想std :: sort做一个qsort,通过值将函数传递给递归调用等).

您还偶然发现了每个人都使用的确切解决方案:让仿函数保持对状态的引用,因此所有副本在需要时都指向相同的状态.

我觉得这很讽刺:

但是这使得不可能使用不可变对象的"功能"风格,而且通常不那么好.

...因为整个问题都取决于你有一个复杂的有状态函子,创建副本是有问题的.如果您使用"功能"样式的不可变对象,这将是一个非问题 - 额外的副本不会成为问题,是吗?