gpt4 book ai didi

c++ - 防止不必要的 C++ 仿函数对象复制

转载 作者:太空宇宙 更新时间:2023-11-04 12:30:34 27 4
gpt4 key购买 nike

我有一个类,它累积有关一组对象的信息,并且可以充当仿函数或输出迭代器。这使我可以执行以下操作:

std::vector<Foo> v;
Foo const x = std::for_each(v.begin(), v.end(), Joiner<Foo>());

Foo const x = std::copy(v.begin(), v.end(), Joiner<Foo>());

现在,理论上,编译器应该能够使用 copy elision and return-value optimizations这样只需要创建一个 Joiner 对象。然而,在实践中,该函数会创建一个拷贝以对其进行操作,然后将其复制回结果,即使是在完全优化的构建中也是如此。

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

Joiner<Foo> joiner;
Foo const x = std::copy(v.begin(), v.end(), joiner);

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

x = std::copy<Container::const_iterator, Joiner<Foo>&>(...));

我可以通过在 std::inserter 风格的仿函数中使用对状态的引用而不是状态本身来使拷贝便宜,导致这样的事情:

Foo output;
std::copy(v.begin(), v.end(), Joiner<Foo>(output));

但这使得无法使用不可变对象(immutable对象)的“函数式”风格,而且通常也不是那么好。

有没有办法鼓励编译器省略临时拷贝,或者让它一直传递引用并返回相同的引用?

最佳答案

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

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

我觉得这很讽刺:

But this makes it impossible to use the "functional" style of immutable objects, and just generally isn't as nice.

...因为这整个问题的前提是你有一个复杂的有状态仿函数,创建拷贝是有问题的。如果您使用的是“函数式”样式的不可变对象(immutable对象),这将不是问题 - 额外的拷贝不会成为问题,对吗?

关于c++ - 防止不必要的 C++ 仿函数对象复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58774493/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com