这是我的问题。我有一个以struct
为输入的函数,分配一个新的struct
然后返回它。 struct
具有以下内容
struct Data {
std::vector<custom_type> vector_vars;
std::string key;
std::map<std::string, Data*> index;
};
vector_vars
的大小为500-1000。如果相关的是this class,则为custom_type。 index
帮助我按Data
访问不同的key
结构。这就是功能。
Data func(Data inputData) {
Data outputData;
//compare values with inputData
//change some values in Data struct
return outputData
}
我是否使用堆栈分配并将其返回以便将其复制到RHS。这是否可取,因为复制可能会产生很多开销?
我可以在函数内返回在堆栈上分配的struct的引用/指针吗?
建议在此使用动态分配(可能与std::shared_ptr
一起使用)以提高效率吗?
答案 0 :(得分:14)
按值返回对象。复制省略是一种优化,标准允许编译器删除不必要的副本。在C ++ 03中,编译器几乎肯定会删除该副本。在C ++ 11中,副本将首先被视为移动(它将反过来移动其内容),甚至可能被删除。
在具有类返回类型的函数中的
return
语句中,当表达式是具有相同cv-unqualified的非易失性自动对象(函数或catch子句参数除外)的名称时键入函数返回类型,通过将自动对象直接构造为函数的返回值,可以省略复制/移动操作
具体来说,当此标准导致复制省略时,通常称为命名返回值优化,return value optimization的形式。
因此,这里最惯用且性能最友好的选择是按价值返回。当然,如果您度量,即使在按值返回优化的情况下是,那么您可以考虑动态分配(参见第3点)。
< / LI>不,您不应该返回指向局部变量的引用或指针。具有自动存储持续时间的对象(您在堆栈上称为分配的对象)将不再存在。引用或指针将悬空。以任何有意义的方式使用它将导致未定义的行为。
不,如上所述,建议按值返回。但是,如果您确实需要,可以动态分配Data
并通过智能指针返回它。这里首选的智能指针是std::unique_ptr
,因为你的功能是将所有权传递给调用函数(不共享所有权)。
答案 1 :(得分:2)
outputData
可以移动到返回值,或者可以省略此移动。在任何情况下都不会有任何昂贵的副本。 inputData
的副本似乎没有必要,也许您应该将其作为Data const& inputData
传递。答案 2 :(得分:2)
Data func1(Data inputData) {
Data outputData;
return outputData
}
按值Data
获取对象,并创建另一个Data
实例,然后按值返回。因此,不仅在返回outputData
时,而且在收到inputData
时创建副本。在按值返回时不要担心性能,有一些机制可以处理它(值得一提的是 copy elision 和可能的返回值优化)。我建议您通过引用inputData
来Data func1(const Data& inputData)
。
这是否可取,因为复制可能会产生大量开销?
经验法则:除非遇到性能问题,否则不要担心代码的性能。
我可以在函数中返回在堆栈上分配的struct的引用/指针吗?
不要在该函数范围内定义自动存储持续时间的对象返回引用/指针。一旦执行超出范围,对象就会被破坏,因此您将最终得到悬空指针(无效引用),这将导致未定义的行为
建议使用动态分配来提高效率吗?
尽可能避免动态分配。不是因为效率,而是为了代码中的内存管理。关注RAII idiom并避免自己处理难看的内存管理。
答案 3 :(得分:1)
您可以重写func()
以返回Data*
而不是Data
。当然,复制Data*
要比复制Data
要快得多。但在那之前:你关心吗?这个功能在程序初始化期间运行一次,占用挂钟时间的十分之一,或者您希望每帧调用一次,还是什么?
当您编写程序或优化现有程序时,您的目标应始终是使其“足够快”(并且“足够响应”,但现在不要介意)。 “足够快”的定义变化很大:在模拟中,您可能乐于每小时处理1TB的数据,而在视频游戏中,您需要每16毫秒向玩家显示一个新的图形帧。
那么:只有堆栈分配,你的程序“足够快”吗?如果是,请不要管它。如果不是,请改用动态分配。一般来说,返回指针而不是大结构是很好的C ++风格,但是在你还在学习时你不应该担心。让它工作,做对,然后快速。