当我尝试返回const引用时,为什么会发生矢量复制?
Why is a vector copy occurring when I try to return a const reference?
我正在测量我在调试模式下运行的一个小演示的性能。这些操作似乎花费了很长时间,并且正在引发复制操作(或者在调试时看起来是这样):
// Get access to the vertices and faces
auto vertices = t.GetVertices();
auto faces = t.GetFaces();
该函数的实现如下:
std::vector<glm::vec3> const& GetVertices() const { return vertices_; }
std::vector<glm::ivec3> const& GetFaces() const { return faces_; }
在包含以下私有成员的类中:
private:
std::vector<glm::vec3> vertices_;
std::vector<glm::ivec3> faces_;
无论出于什么原因,我希望返回一个const引用几乎不会带来任何性能损失,但是这个操作似乎确实使程序陷入了困境。我遗漏了什么?这是否在发布模式下得到了优化,但总是在调试模式下发生? 为什么要复制内容?
vertices
和faces
的类型分别为std::vector<glm::vec3>
和std::vector<glm::ivec3>
。初始化它们时,编译器需要从返回的引用中复制内容。
编译器假定当数据成员vertices_
发生变化时,不希望vertices
的内容发生变化;因为这是你声明变量的方式。
我怎样才能避免这种情况的发生?
如果你想将它们声明为引用,你必须明确地这样说:
auto const& vertices = t.GetVertices ();
auto const& faces = t.GetFaces ();
如何推断出faces
和vertices
的类型?
有了表达式auto foo = init
, foo
将具有为下面模板函数的实参(称为deduce_type (init)
)推导出来的类型作为其形参。
template<class T> void deduce_type (T);
<一口>一口>
// auto vertices = t.getVertices ();
deduce_type (t.getVertices ()) // imaginary call, T = std::vector<glm::vec3>
是否有一些变通办法,使我总是得到确切的类型?
不,目前还没有,但在即将到来的 c++ 标准中( c++ 14),你将能够做以下事情,结果将是你不准确地期望你的原始代码做的:
decltype(auto) vertices = t.GetVertices ();
// ^-- vertices is of type `std::vector<glm::vec3> const&`
必须记住,用/to另一个对象赋值或初始化一个对象,将(以某种方式)以该对象的副本结束。当你给出的函数返回常量引用时,它们被赋值(或复制)给新的实例化。
您可以通过使用指针来避免这种情况(这将在堆栈上为指针分配内存,但在我看来这是一个名义因素),或者您可以使用move构造函数。我不知道我移动构造函数是否会工作,在这种情况下,但我最初的想法是它不会(因为分配的值应该是const)。
相关文章:
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 为什么复制而不是移动数据元素?
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 为什么C++在将一个对象复制到另一个对象时需要对这两个对象进行低级常量限定
- 为什么默认复制函数在按值发送参数时不调用?
- 为什么调用复制构造函数而不是移动构造函数?
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- 为什么使用析构函数会使类不可复制?
- 为什么当我尝试返回引用时,我的对象仍然被复制
- 为什么我们在C++中使用手动复制构造函数?
- 为什么我的运算符 + 重载尽管是通过引用传递的,但仍调用我的复制构造函数?
- 如果 iostream 对象不可复制,为什么以下代码是合法的?
- 为什么我的代码在尝试复制字符数组时引发 C6386 错误?
- 为什么我可以使用 memcpy 将一个对象变量复制到另一个对象变量
- C++复制 c'tor 现在确实会采取行动。 不清楚为什么
- 为什么 std::string s = "123" 当不涉及副本时被视为复制初始化?
- 为什么此指针被错误地复制?为什么分段错误没有更早发生
- 用lambda创建std::函数会导致对lambda对象的多余复制——为什么?