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看起来模板类型推断本身是一个相当复杂的主题。我能记得有什么经验法则来确保我不会再把事情搞砸吗?@aardvarkkauto
永远不会被推断为引用、常量或数组。(您可以添加引用和常量,如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&`