c++ 以最佳方式返回结构和向量
Posted
技术标签:
【中文标题】c++ 以最佳方式返回结构和向量【英文标题】:c++ return structures and vectors optimally 【发布时间】:2019-10-29 17:36:17 【问题描述】:我正在阅读很多关于 C++ 优化的不同内容,但我很困惑。我会很感激一些帮助。基本上,当我将向量和结构作为参数传递或返回向量和结构时,我想弄清楚是否需要指针。
假设我有一个包含 2 个元素的结构:一个 int,然后是一个整数向量。我将在函数中本地创建这个结构,然后返回它。这个函数会被多次调用,每次都会生成一个新的结构体。我想保留在类成员中创建的最后一个结构(例如 lastStruct_)。因此,在返回结构之前,我可以以某种方式更新 lastStruct_。
现在,最好的方法是什么,知道结构中的向量可能非常大(需要避免复制)。结构中的向量是否需要是指针?如果我想通过创建 get_lastStruct() 方法将 lastStruct_ 共享给其他类,我应该返回对 lastStruct_ 的引用、指针还是不关心它? lastStruct_ 应该是共享指针吗?
这让我很困惑,因为显然 C++ 知道如何避免复制,但我也看到很多人建议使用指针,而其他人则说指向向量的指针根本没有意义。
struct MyStruct
std::vector<int> pixels;
int foo;
class MyClass
MyStruct lastStruct_;
public:
MyStruct create_struct();
MyStruct getLastStruct();
MyClass::create_struct()
MyStruct s = std::vector<int>(100, 1), 1234;
lastStruct_ = s;
return s;
MyClass::getLastStruct()
return lastStruct_;
【问题讨论】:
所以它取决于 C++ 的版本,任何比 C++11 更新的东西都应该做 RVO。较新的版本甚至可以保证复制省略。 “很多人推荐使用指针”。他们只是还没有收到备忘录。 所以我的理解是结构中的向量应该是一个普通的向量。该结构应正常返回(返回 the_struct)。属性 lastStruct_ 应该是一个普通的结构。我会用正常的分配更新lastStruct_ = the_struct。最后,当我通过 getter 分享这个 lastStruct_ 时,我会简单地返回 lastStruct_ ?真的那么简单吗(C++>11真的那么好吗? 【参考方案1】:如果您尝试删除的唯一副本是从工厂函数返回时发生的副本,我想说直接包含向量会更快一直。
为什么?两件事情。返回值优化 (RVO/NRVO) 将消除返回时对临时人员的任何需求。这对于几乎所有情况都足够了。
当返回值优化不适用时,移动语义将适用。返回一个命名变量(例如:return my_struct;
)将在 NRVO 不适用的情况下进行隐式移动。
那么为什么它总是比共享指针快呢?因为在复制共享指针时,必须取消引用控制块以增加所有者计数。而且由于它是原子操作,因此增量不是免费的。
此外,使用共享指针会带来共享所有权和非本地性。如果要使用共享指针,请使用指向 const 数据的指针来恢复值语义。
现在您添加了代码,您想做什么就更清楚了。
这里无法绕过副本。如果您测量性能下降,则包含std::shared_ptr<const std::vector<int>>
可能是解决方案,因为您将保持值语义但避免向量复制。
【讨论】:
感谢您提供详细信息。我相信我正在关注结构中的向量。该结构被返回,然后超出范围,因此 c++ 知道如何优化它。但是对于包含最后创建的结构的类属性 lastStruct,这个总是在范围内。因此,当我尝试将此变量共享给其他类以便他们可以访问最后可用的数据时,如果我只是return lastStruct;
那么 c++ 是否需要复制它?一个举动会“窃取”我想要的数据。
@XDD 如果您想要一个私有数据成员和一个 getter,那么对 const 的引用将消除复制的需要,因为在这种情况下return nonLocal
将始终复制。除非你这样做std::move(nonLocal)
,但我会避免这样做。
好的,我明白了。我认为这回答了我的大部分问题。 C++ 足够智能,可以在返回超出范围的对象时避免复制。然后引用 const 将使共享私有成员 (lastStruct) 变得快速而简单。最后一个问题是私有成员 lastStruct 的更新。在创建本地结构然后返回的工厂中,我想更新 lastStruct。有没有办法避免那里复制?
如果您执行my_member = make_struct()
,则没有副本,因为make_struct()
返回的对象是临时的。在这种情况下,这是一个举动。
@XDD 哦,我刚刚看到带有代码的示例,我知道你说的最后一个结构是什么意思。不,您基本上想要一个副本,因此 C++ 无法帮助您删除它。如果你真的想避免整个向量的副本,我会尝试std::shared_ptr<const std::vector<int>>
来保持值语义。即便如此,我会将共享指针隐藏为私有成员。以上是关于c++ 以最佳方式返回结构和向量的主要内容,如果未能解决你的问题,请参考以下文章