5

这是我的问题。我有一个函数struct作为输入,分配一个新的struct然后返回它。有以下struct内容

struct Data {
std::vector<custom_type> vector_vars;
std::string key;
std::map<std::string, Data*> index;
};

vector_vars大小为 500-1000。custom_type 如果相关是此类index帮助我访问不同的Data结构key。这就是功能。

Data func(Data inputData) {

 Data outputData;
//compare values with inputData
//change some values in Data struct
 return outputData
}
  1. 我是否使用堆栈分配并将其返回,以便将其复制到 RHS。这是可取的,因为复制可能会产生很多开销?

  2. 我可以返回一个引用/指针,指向函数内堆栈上分配的结构吗?

  3. 为了提高效率,是否建议在这里(可能与)使用动态分配std::shared_ptr

4

4 回答 4

14
  1. 按值返回对象。复制省略是标准允许编译器进行的一种优化,可以删除不必要的副本。在 C++03 中,编译器几乎肯定会忽略副本。在 C++11 中,复制首先会被视为一个移动(这反过来会移动其内容),甚至可能会被忽略。

    return具有类返回类型的函数的语句中,当表达式是具有与函数返回类型相同的 cv 非限定类型的非易失性自动对象(函数或 catch 子句参数除外)的名称时,可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作

    具体来说,当这个标准导致复制省略时,它通常被称为命名返回值优化,返回值优化的一种形式

    所以这里最惯用和性能友好的选择是按值返回。当然,如果你测量到即使在优化下按值返回也是一个问题,那么当然,你可以考虑动态分配(见第 3 点)。

  2. 不,您不应该返回指向局部变量的引用或指针。具有自动存储持续时间(您所说的在堆栈上分配)的对象将不再存在。引用或指针将悬空。以任何有意义的方式使用它都会导致未定义的行为。

  3. 不,如上所述,建议按值返回。但是,如果您真的需要,您可以动态分配Data并通过智能指针返回它。这里首选的智能指针是 astd::unique_ptr因为您的函数正在将所有权传递给调用函数(不共享所有权)。

于 2013-03-01T16:06:58.880 回答
2
  1. 实际上,这里可能会发生两种快速操作中的一种:或者outputData可以移动到返回值中,或者可以省略这个移动。在这两种情况下都不会有任何昂贵的副本。的副本inputData似乎没有必要,也许您应该将其传递为Data const& inputData.
  2. 您可以这样做,但这会导致未定义的行为。
  3. 不会。动态分配可能更不安全、更慢、更混乱并且通常更糟。
于 2013-03-01T16:06:41.407 回答
2
Data func1(Data inputData) {
    Data outputData;
    return outputData
}

按值获取类型的对象Data并创建另一个实例,Data然后按值返回。因此,不仅在outputData返回时创建副本,而且inputData在接收时创建副本。不用担心按值返回时的性能,有一些机制会处理它(值得一提的是复制省略和可能的返回值优化)。我建议您inputData通过参考通过:Data func1(const Data& inputData).

这是可取的,因为复制可能会产生很多开销?

经验法则:除非遇到性能问题,否则不要担心代码的性能。

我可以返回一个引用/指针,指向函数内堆栈上分配的结构吗?

Don't return a reference / pointer to the object with automatic storage duration defined within the scope of that function. The object is destructed once the execution goes out of scope, so you will end up with dangling pointer (invalid reference) which will lead to undefined behavior

Is it advisable to use dynamic allocation instead here for efficiency?

Avoid dynamic allocation wherever possible. Not because of efficiency, but for the sake of the memory management within your code. Follow RAII idiom and avoid handling the ugly memory management on your own.

于 2013-03-01T16:12:36.723 回答
1

You could rewrite func() to take return a Data* instead of a Data. Certainly it's much faster to copy a Data* than it is to copy a Data. But before that: do you care? Does this function run once during program initialization, taking a tenth of second of wall clock time, or do you expect to call it once a frame, or what?

When you're writing a program, or optimizing an existing one, your goal should always be to make it "fast enough" (and "responsive enough", but never mind that for now). The definition of "fast enough" varies a lot: in a simulation you might be happy to crunch one terabyte of data per hour, while in a video game you need to show the player a new graphics frame every 16 milliseconds.

So: is your program "fast enough" with just stack allocation? If it is, leave it alone. If it's not, use dynamic allocation instead. In general, it's good C++ style to return pointers instead of large structs, but you shouldn't worry about that while you're still learning. Make it work, make it right, then make it fast.

于 2013-03-01T21:47:24.087 回答