C++0x:当一个临时对象等于另一个临时对象时

发布于 2025-01-01 09:54:19 字数 1160 浏览 0 评论 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。

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

附:我的编译器是g++4.7 20110430

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;
}

In this example, f() and g() respectively return a temporary object, so f()=g() results in an expression of temporary object equal to temporary object. I would have expected that the answer is 14 if the value is correctly copied. However, it is NOT calling the copy assignment, BUT calling the move assignment! As a result, the answer is not 14.

This makes me really confused. Although the returning objects from f() and g() are temporary, they are sharing some information with some other objects. It implies the temporary objects might be doing some works shortly for the shared information. So I am supposed that semantically calling copy assignment would be the correct behaviors.

ps. My compiler is g++4.7 20110430

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏九 2025-01-08 09:54:20

您正在创建一个具有指向同一位置的指针的实例。使用F::operator() 创建的实例共享指针本身。

f()=g() 相当于 f().operator=(g()) 并且 g() 创建一个临时实例,因此调用是正确的移动作业。

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

我不确定你对这些复杂的代码做了什么,但你最好用 std::shared_ptr 或其他东西重写代码。

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

You are creating an instance which has a pointer pointing the same location. The instance created with F::operator() does not share the pointer itself.

f()=g() is equivalent to f().operator=(g()) and g() creates a temporary instance, so it is correct to call move assignment.

The problem is that f has a dangling pointer after the execution of f()=g(). f() creates an temporary instance, it deletes the pointer in the move assignment operator, but f itself still has a pointer which points the deleted location.

I'm not sure what you're doing with those complicated code but you'd better rewrite the code with std::shared_ptr or something.

p.s. You don't need std::move in returning an instance. Your compiler has RVO features if you didn't turn these off.

暖心男生 2025-01-08 09:54:19

您的 operator() 返回一个值,而不是引用或指针。因此,它返回一个临时值。临时变量隐式绑定到 &&优先(他们是唯一这样做的类型)。因此,如果有一个移动赋值运算符供他们使用,他们会更喜欢使用它。

您的问题是,当您在 operator() 函数中执行此操作时,您停止了做合理的事情:

F cpy_f( data );

采用指针的 F 构造函数使用指针值本身,有效地采用指针。此时,您现在有两个 F 实例指向相同的数据。

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

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

Your operator() returns a value, rather than a reference or pointer. Therefore, it returns a temporary. Temporaries implicitly bind to && preferentially (they are the only types to do so). Therefore, if there is a move assignment operator for them to use, they will prefer to use it.

Your problem is that you stopped doing reasonable things when you did this in your operator() function:

F cpy_f( data );

The constructor of F that takes a pointer uses the pointer value itself, effectively adopting the pointer. At that moment, you now have two F instances that point to the same data.

If that's something you want to be reasonable, then you cannot have your move assignment operator delete the pointer. You need to reconcile the fact that you can have two F instances that point to the same thing. The two need to share ownership of the pointer. So... how do you plan to do that?

I would suggest getting rid of this constructor altogether. It will only create more problems for you. I would also suggest using a std::unique_ptr<int> data; instead of a naked pointer. That way, you don't have to write a move constructor/assignment operator (though you do need a copy constructor/assignment operator).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文