我有一个包含我期望使用的数据的类,所以我认为最好返回一个const引用。但是,考虑到一些参数,我可能需要动态创建新数据。我已经看到你可以像这样返回一个临时的常量引用:
class Foo {
public:
Foo() { ... } //Initialize data
LARGE_DATA getData(bool param1, bool param2) {
if (...) { // For some crazy function of the parameters
LARGE_DATA newData = ...; // Create new data and return it
return newData
}
return data; // Usually, will just use the default value
}
private:
LARGE_DATA data;
};
void bar() {
Foo f;
const LARGE_DATA& data = f.getData();
... // Process data (read-only)
}
但这似乎会复制data
。我想做这样的事情:
class Foo {
public:
Foo() { ... } //Initialize data
const LARGE_DATA& getData(bool param1, bool param2) {
if (...) { // For some crazy function of the parameters
LARGE_DATA newData = ...; // Create new data and return it
return newData
}
return data; // Usually, will just use the default value
}
private:
LARGE_DATA data;
};
void bar() {
Foo f;
const LARGE_DATA& data = f.getData();
... // Process data (read-only)
}
所以要避免不必要的副本。 Visual Studio并没有抱怨这个,但是g ++确实(并且可能是这样)。什么是正确的方法?
答案 0 :(得分:1)
我想我理解你的困境。在您的第一个实现中,您依赖于描述here的C ++特性,其中从函数返回的临时(在这种情况下为newData
)在保存对它的const引用时延长其生命周期。由调用函数堆栈。但是如果返回data
而不是newData
,它将创建一个副本,然后将该副本作为临时副本返回,这是您不想要的。
您的第二个实现尝试通过返回引用来阻止复制data
,但由于newData
,这会因g ++而中断。您不再返回名为newData
的临时对象,您现在正在返回对它的引用,根据g ++,它不符合终身扩展的条件。
我看到了两种方法。您可以将getData()
分成两个方法,一个通过返回引用返回data
,另一个通过值返回newData
,从而创建临时值。或者您可以将newData
保存为类的数据成员,返回对data
的引用,并在每次需要重新计算时将其覆盖,但是只有在您只需要在newData
的连续调用之间读取给定的getData()
值。
答案 1 :(得分:0)
你应该通过在newData
中的某个位置存储Foo
来保留所有权,然后再返回对它的引用(可能在你懒洋洋地初始化的地图中,其中键是函数参数的表示,比如在这种情况下为std::pair<bool, bool>
,或者使用一些引用计数智能指针(C ++ 11中的boost::shared_ptr
/ std::shared_ptr
)来保存newData
如果您不想保留所有权(也将data
成员包装在智能指针中)。
答案 2 :(得分:0)
对我而言,它似乎是指针的用例。
让方法getData
返回一个指针,如果你不想修改返回的对象,让它返回一个const
指针。指针指向的内容 - 成员数据或动态创建的临时数据 - 可以在运行时决定。这也可以避免在方法返回时复制数据。
在这种方法中,您需要注意的一件事是您创建的临时数据必须在堆上,否则返回的指针将指向超出范围的内存。