所以我写了一些代码,我有类似的东西:
class Box
{
private:
float x, y, w, h;
public:
//...
Rectangle & GetRect( void ) const
{
return Rectangle( x, y, w, h );
}
};
稍后在一些代码中:
Rectangle rect = theBox.GetRect();
哪个在我的调试版本中有效,但在发行版中有“问题”通过引用返回Rectangle - 我基本上得到了一个未初始化的矩形。 Rectangle类有一个=运算符和一个复制构造函数。在没有弄清楚为什么会破坏的情况下,我实际上更感兴趣的是通过引用返回(新)对象的正确方法,以便分配复制到变量。我只是傻吗?不应该这样做吗?我知道我可以返回一个指针,然后取消引用,但我不愿意。我的某些部分感觉像按值返回会导致对象的冗余复制 - 编译器是否会解决并优化它?
这似乎是一个微不足道的问题。经过多年的C ++编码后,我感到尴尬,我不知道这一点,所以希望有人可以为我清除这一点。 :)
答案 0 :(得分:24)
您无法返回对堆栈上临时对象的引用。您有三种选择:
请注意,当您按照下面的代码中的值返回时,编译器应优化分配以避免复制 - 即,它将通过优化create + assign + copy到create中来创建单个Rectangle(rect)。这仅在从函数返回时创建新对象时有效。
Rectangle GetRect( void ) const
{
return Rectangle( x, y, w, h );
}
Rectangle rect = theBox.GetRect();
答案 1 :(得分:15)
不,你不能这样做。基本上,您在此示例中尝试执行的操作是返回对堆栈上的临时变量的引用。返回引用时,它指向的变量将被销毁,因此引用无效。
答案 2 :(得分:7)
按值返回对象(参见下面的示例)实际上可能比您想象的要便宜。编译器通常会优化额外的副本。这称为return value optimization。
Rectangle GetRect( void ) const
{
return Rectangle( x, y, w, h );
}
答案 3 :(得分:3)
是否有正确的方式来返回新的 C ++中引用的对象实例?
不,不是参考。有两种方法可以创建新对象:
在堆栈上:
Rectangle makeRect()
{
return Rectangle(x, y, w, h);
}
Rectangle r = makeRect(); // return by value
在堆上:
Rectangle * makeRect()
{
return new Rectangle(x, y, w, y);
}
Rectangle * r = makeRect(); // returned a pointer, don't forget to delete it later
为什么不是这样的?
class Box
{
private:
Rectangle mRectangle;
public:
Box(float x, float y, float w, float h) :
mRectangle(x, y, w, h) // Forgive me for making assumptions
// about the inner workings of your
// code here.
{
}
const Rectangle & GetRect() const
{
return mRectangle;
}
};
Rectangle rect = theBox.GetRect();
“任务”现在应该有效。 (从技术上讲,这不是赋值运算符,而是要调用的复制构造函数。)
希望提供帮助
答案 4 :(得分:2)
Box
课程内部成员的引用(请Rectangle
成员。建议返回const
引用。)Rectangle
。请注意,使用惯用语return SomeClass(a,b,c);
可能会在合适的编译器上触发return value optimization (RVO)。检查您的std::complex
实施细节。
答案 5 :(得分:2)
你可能会对临时生命的概念感到困惑。考虑:
void f1( const A & a ) {
}
A f2() {
return A;
}
f1( f2() );
这是好的代码,标准说f2创建的无名临时文件必须挂起足够长的时间才能在f1中使用。
但是,你的情况有所不同。函数返回的东西是引用,因此无名临时也是引用。该引用必须挂起足够长的时间才能有用,但它所引用的内容不需要。
答案 6 :(得分:2)
这是不可能的。引用是指针的另一种形式,实际上你返回一个已被销毁的对象的地址(析构函数被调用),甚至可能在调用者获得控制权时被覆盖。
你可以
答案 7 :(得分:0)
如果矩形按位看起来像Box,即由四个浮点数组成(但有不同的成员函数),你可以使用 reinterpret_cast ,虽然我根本不推荐它:
const Rectangle & GetRect( void ) const
{
assert(sizeof(Rectangle) == sizeof(Box));
return reinterpret_cast <Rectangle> (*this);
}
答案 8 :(得分:0)
我们可以使用auto_ptr,如果我们想使用新的和安全的内存泄漏
class Box {
private: float x, y, w, h;
public:
//...
std::auto_ptr<Rectangle> GetRect( void ) const
{
return std::auto_ptr<Rectangle> ( new Rectangle( x, y, w, h ));
}
};