C++ 返回时如何避免复制

C++ 返回时如何避免复制,c++,c++11,rvalue-reference,C++,C++11,Rvalue Reference,我有一个返回向量或集合的函数: set<int> foo() { set<int> bar; // create and massage bar return bar; } set<int> afoo = foo(); 谢谢 退房。现代编译器将优化这种情况,在这种简单的情况下,不会在任何主要编译器上进行复制 原则上,您也可以在函数外部创建对象,然后调用函数并通过引用将对象传递给它。这是避免复制的老办法,但现在不需要了。我通常通过使用

我有一个返回向量或集合的函数:

set<int> foo() {
    set<int> bar;
    // create and massage bar
    return bar;
}

set<int> afoo = foo();
谢谢

退房。现代编译器将优化这种情况,在这种简单的情况下,不会在任何主要编译器上进行复制


原则上,您也可以在函数外部创建对象,然后调用函数并通过引用将对象传递给它。这是避免复制的老办法,但现在不需要了。

我通常通过使用函数签名来解决这个问题

void foo(set<int> *x)
void foo(集合*x)
只需通过引用传递它,或者注释中已经提到了其他选项

编辑:我更改了参数类型,以说明x可以更改

      set<int> s;
      foo(&s);
set;
foo&s;
只有使用旧编译器时,才首选此选项。我想有些项目可能就是这样


而且,更好的方法是在c++11中使用移动语义。或者在现代编译器中返回容器并查看RVO。

< P>调制解调器C++编译器将实现:给定类型<代码> T <代码>:

  • 如果T具有可访问的复制或移动构造函数,则编译器可能 选择删除副本。这就是所谓的(命名),它甚至在C++11之前就已经指定了,并且是 大多数编译器都支持
  • 否则,如果T有a,则移动T(,因为C++11)
  • 否则,如果T具有复制构造函数,则复制T
  • 否则,将发出编译时错误

您现在拥有的不会在C++11中复制任何副本。它可能会采取一些行动,但即使是那些行动,也几乎肯定会通过“如何避免我返回时的复制”-使用不超过10年前发布的编译器编译。@MooingDuck:在我工作的地方,“C++”的意思是“C++03”,这在2020年之前不太可能改变。我怀疑对于90的专业C++程序员来说也是如此。(大型组织使用了其中的大部分,大型组织的发展非常缓慢。)事实上,C++11很可能成为“C++99”。尼莫:我认为你夸大了没有C++11的组织的数量。即使你没有,官方的C++也值得被提及,即使答案也提供了C++ 03的细节。@ Lealy:问题具体地讲C++ 11。我查看了编辑历史,没有证据表明它没有专门询问C++。所以,是的,任何不提及右值引用的答案都是有缺陷的。我对此投赞成票,因为这是唯一建议传入输出参数的答案。一个完美的答案应该包括RVO和move构造函数。几乎有人试图否决它提出的输出参数。@DeadMG为什么输出参数如此糟糕?在许多情况下,在现代编译器上使用输出参数比从函数返回结果的效率要低。它还可能会降低代码的可读性,因为在许多情况下,它会迫使您使用临时变量,而返回值可以轻松地传递给其他函数或直接在表达式中使用。采用输出参数的函数是不可组合的,而且灵活性也较低。如果明天,你想要一个无序的集合,我必须改变我所有的呼叫代码。如果我有
auto set=foo()我什么也没变。输出参数只是模糊不清。如果要返回多个值,请使用元组,这就是它的用途。这也正是编译器实现的,按值返回为。特别是因为整个shebang是不必要的,因为move语义。如果我错了,请纠正我,但是只有当您直接在return语句中构造对象时,AFAIK返回值优化才有效,如下所示:
return(set)(…)智能编译器可能会将问题中的代码转换成这种形式,但对于更复杂的函数,我认为它将无法工作。@cmaster,在OP的情况下,RVO也将适用。阅读我回答中有关RVO的wiki链接。:)@cmaster:在返回命名变量的情况下优化副本通常称为NRVO,命名为返回值优化,大多数编译器多年前就已经实现了它。@JohannesD:很高兴听到这个消息,但在某些情况下仍然不可能,不是吗?也就是说,你仍然要考虑它,以确保副本是真正优化了吗?
      set<int> s;
      foo(&s);