2012-02-02 168 views
0
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.的C++ 0x:当一个临时对象等于另一个临时对象

这让我很困惑。尽管从f()g()返回的对象是临时的,但他们与其他一些对象共享某些信息。这意味着临时对象可能会很快为共享信息做一些工作。所以我认为在语义上调用复制分配将是正确的行为。

ps。我的编译器是g ++ 4.7 20110430

+2

添加一个析构函数,你会看到很大的问题 – 2012-02-02 05:53:05

+0

遵循3/5规则可能会有所帮助http://stackoverflow.com/questions/4782757/rule-of-three-becomes-rule-of - 五 - 与-C11 – Cubbi 2012-02-02 05:57:03

回答

0

你正在创建一个实例,它有一个指向同一位置的指针。用F::operator()创建的实例确实是而不是共享指针本身。

f()=g()等价于f()。operator =(g())和g()创建一个临时实例,所以调用move assignment是正确的。

问题是f在执行f()=g()后有一个悬挂指针。 f()创建一个临时实例,它删除移动赋值操作符中的指针,但f本身仍然有一个指向已删除位置的指针。

我不确定你在处理那些复杂的代码,但是你最好用std::shared_ptr或者其他东西重写代码。

p.s.您不需要std::move来返回实例。如果您没有关闭这些功能,则您的编译器具有RVO功能。

4

您的operator()返回一个值,而不是参考或指针。因此,它返回一个临时的。临时含蓄地优先结合到& &(它们是唯一的类型)。因此,如果有移动赋值运算符供他们使用,他们会更喜欢使用它。

你的问题是,你停止了,当你在你的operator()功能做这个做合理的事情:

F cpy_f(data); 

F,需要一个指针构造函数使用指针值本身,有效地采用指针。那时候,你现在有两个两个F指向相同数据的实例。

如果这是你想要合理的事情,那么你不能有你的移动赋值操作符删除指针。你需要协调一个事实,即你可以有两个指向同一事物的实例。这两者需要共享指针的所有权。所以...你打算怎么做?

我建议完全摆脱这个构造函数。它只会给你造成更多的问题。我也建议使用std::unique_ptr<int> data;而不是裸指针。这样,您不必编写移动构造函数/赋值运算符(尽管您确实需要复制构造函数/赋值运算符)。