来自 Java 背景,我试图理解 C++ 中的指针/引用。我正在尝试从函数返回一个向量。写作:
vector<char*> f(){
vector<char*> vec;
return vec;
}
会返回向量的副本,对吗?更好的方法是返回指向向量的指针,如下所示:
vector<char*>* f(){
vector<char*>* vec = new vector<char*>;
return vec;
}
我是正确的,还是完全错误的?
在 C++03 中,按值返回最有可能导致 RVO(返回值优化),这将省略不必要的副本。在 C++11 中,移动语义将负责复制。
那么,为什么首先按值返回?因为它可以防止具有动态生命周期的不必要的对象。您的示例代码也不尊重您的函数用户可能想要使用的任何分配策略。
一般来说,即使在 C++11 中,返回一个容器仍然是一个坏主意:它将用户限制在该特定容器中,因为不可能跨容器移动,只能复制。标准库用OutputIteratorS
. 您的算法很可能会写成:
template<typename OutputIterator>
OutputIterator f(OutputIterator o);
这样你就可以从容器中抽象出来,也可以规避最初的问题。
你错了,你不想在 C++ 中这样做。几乎每个 C++ 编译器都有所谓的命名返回值优化,这将(有效地)vec
通过为堆栈上的返回值分配空间来移动而不是复制,然后基本上“就地”构造。这消除了开销。
维基百科关于此的文章给出了合理的概述。
我是正确的,还是完全错误的?
这是完全错误的,至少在存在移动语义的 C++11 中,只要您不需要创建返回值的别名(这似乎不是您的情况,即使是这样,也会可能需要使用智能指针而不是原始指针)。
现在可以按值返回向量了。大多数时候,即使在 C++98 中,编译器也会忽略对复制构造函数的调用(以及 C++11 中的移动构造函数)。这称为(命名的)返回值优化。
在 C++11 中,标准库的所有容器都支持移动构造函数,因此即使没有省略复制或移动,按值返回容器也不昂贵。