C++ 为什么在我尝试返回常量引用时会发生向量复制?

C++ 为什么在我尝试返回常量引用时会发生向量复制?,c++,vector,stl,C++,Vector,Stl,我正在测试我在调试模式下运行的一个小演示的性能。这些操作似乎需要很长的时间,并且会导致复制操作(或者调试时出现的情况): 该功能的实现如下: std::vector<glm::vec3> const& GetVertices() const { return vertices_; } std::vector<glm::ivec3> const& GetFaces() const { return faces_; } std::vector

我正在测试我在调试模式下运行的一个小演示的性能。这些操作似乎需要很长的时间,并且会导致复制操作(或者调试时出现的情况):

该功能的实现如下:

std::vector<glm::vec3>  const& GetVertices() const { return vertices_; }
std::vector<glm::ivec3> const& GetFaces()    const { return faces_;    }
std::vector const&GetVertices()const{返回顶点}
std::vector const&GetFaces()const{return faces}
在包含以下私有成员的类中:

private:
  std::vector<glm::vec3>  vertices_;
  std::vector<glm::ivec3> faces_;
private:
std::向量顶点;
std::向量面;
无论出于什么原因,我都希望返回const引用会导致几乎零的性能损失,但这个操作似乎真的让程序陷入困境。我错过了什么?这会在发布模式下得到优化,但总是在调试模式下发生吗?

为什么会复制内容?
顶点
的类型分别为
std::vector
std::vector
。初始化它们时,编译器需要从返回的引用复制内容

如果数据成员
顶点
发生更改,编译器假定您不希望
顶点
的内容发生更改;因为这就是你声明变量的方式


我怎样才能防止这种情况发生? 如果要将它们声明为引用,则必须明确说明:

auto const& vertices = t.GetVertices ();
auto const& faces    = t.GetFaces ();

如何推断
顶点
的类型? 使用表达式
auto foo=init
foo
将使用为以下模板函数的参数推导的类型作为其参数,称为
推断类型(init)

template<class T> void deduce_type (T);
模板空推类型(T);

//自动顶点=t.getVertices();
推断类型(t.getVertices())//假想调用,t=std::vector

是否有一些变通办法,以便我始终能得到准确的类型?

不,不是现在,但是在即将到来的C++标准(C++ 14)中,你将能够做下面的事情,结果将是你不准确地预期你的原始代码要做的:

decltype(auto) vertices = t.GetVertices ();
//              ^-- vertices is of type `std::vector<glm::vec3> const&`
decltype(自动)顶点=t.GetVertices();
//^--顶点的类型为'std::vector const'&`

您必须记住,向另一个对象分配或初始化对象(以某种方式)将以该对象的副本结束。虽然您提供的函数返回常量引用,但它们被分配(或复制)到新的实例化


您可以通过使用指针来避免这种情况(指针将在堆栈上为指针分配内存,但在我看来这是一个标称因子),也可以使用移动构造函数。在这种情况下,我不知道我的move构造函数是否有效,但我最初的想法是它不会起作用(因为赋值应该是const)。

导致复制的不是返回,而是初始化导致复制的新变量。首先,因为您返回了一个引用,所以没有性能损失,除非像这样赋值
std::vector v=get顶点()std::vector&v=GetVertices()有趣--我假设
auto
只是将数据类型神奇地匹配到相关函数调用返回的任何内容。显然不是这样。如何确定
auto
的数据类型?例如,如果函数返回一个常量指针,自动数据类型是否仍然是一个正则向量?@aardvarkk,它与模板类型推断相同。@chris看起来模板类型推断本身是一个相当复杂的主题。我能记得有什么经验法则来确保我不会再把事情搞砸吗?@aardvarkk
auto
永远不会被推断为引用、常量或数组。(您可以添加引用和常量,如refp的答案中所示,但不能添加数组,顺便说一句。)引用和
const
被删除,数组衰减到指针。
auto&&
非常接近精确的类型(它合并了右值引用和右值引用)
                               // auto vertices = t.getVertices ();
deduce_type (t.getVertices ()) // imaginary call, T = std::vector<glm::vec3>
decltype(auto) vertices = t.GetVertices ();
//              ^-- vertices is of type `std::vector<glm::vec3> const&`