struct F
{
private:
int* data;
public:
F( int n )
{
data = new int;
*data = n;
}
F( int* p )
{
data = p;
}
F& operator=( const F& f )
{
*data = *(f.get_data());
return *this;
}
F& operator=( F&& f )
{
delete data;
data = f.data;
f.data = nullptr;
return *this;
}
F& operator=( int n ) { *data = n; return *this; }
F operator()()
{
F cpy_f( data );
return std::move( cpy_f );
}
int* get_data() const { return data; }
};
int main()
{
F f( 12 );
F g( 14 );
f() = g();
cout << *(f.get_data()) << endl;
}
在此示例中,f()
和g()
分别返回一个临时对象,因此f()=g()
会导致临时对象的表达式等于临时对象。如果值被正确复制,我原以为答案是14。但是,不调用复制分配,但调用移动分配!结果,答案不是14。
这让我很困惑。虽然来自f()
和g()
的返回对象是临时的,但它们与其他一些对象共享一些信息。这意味着临时对象可能会很快为共享信息做一些工作。所以我认为在语义上调用复制赋值将是正确的行为。
PS。我的编译器是g ++ 4.7 20110430
答案 0 :(得分:4)
您的operator()
返回一个值,而不是引用或指针。因此,它返回一个临时的。 Temporaries 暗含绑定到&amp;&amp;优先(他们是唯一这样做的类型)。因此,如果有一个移动赋值运算符供他们使用,他们会更喜欢使用它。
您的问题是,当您在operator()
函数中执行此操作时,您已停止做出合理的事情:
F cpy_f( data );
带有指针的F
构造函数使用指针值本身,有效地采用指针。此时,您现在有两个 F
个实例,指向相同的数据。
如果那是你想要合理的东西,那么你不能让你的移动赋值操作符删除指针。您需要协调一个事实,即您可以有两个F
实例指向同一个事物。两者需要共享指针的所有权。那么......你打算怎么做?
我建议完全摆脱这个构造函数。它只会给你带来更多问题。我还建议使用std::unique_ptr<int> data;
而不是裸指针。这样,您不必编写移动构造函数/赋值运算符(尽管您确实需要复制构造函数/赋值运算符)。
答案 1 :(得分:0)
您正在创建一个指针指向相同位置的实例。使用F::operator()
创建的实例不共享指针本身。
f()=g()
等效于f()。operator =(g())和g()
创建一个临时实例,因此调用移动赋值是正确的。
问题是f
在执行f()=g()
后有一个悬空指针。 f()
创建一个临时实例,它删除移动赋值运算符中的指针,但f
本身仍然有一个指向已删除位置的指针。
我不确定你对这些复杂的代码做了什么,但你最好用std::shared_ptr
或其他东西重写代码。
P.S。返回实例时不需要std::move
。如果您没有关闭它们,您的编译器就具有RVO功能。