从不可移动对象的函数返回副本

时间:2014-07-22 19:31:27

标签: c++ c++11 move-semantics

我的一个朋友偶然发现了一个问题

是否有任何方法可以返回可复制但不可移动的对象副本。换句话说,我们可以使以下代码工作吗?

struct A {
    A() = default;
    A(A const&) = default; // copyable
    A& operator=(A const&) = default; // assignable
    A(A &&) = delete; // not movable
    A& operator=(A &&) = delete; // not movable
    ~A() = default;
};

A foo() {
     A a;
     return a;
}

int main() {
    A a(foo()); //will fail, because it calls A(A&&)
    return 0;
}

在我看来,我们不能,因为foo()A&&,因此编译器必须调用A(A&&)。但我想要一些确认。

2 个答案:

答案 0 :(得分:3)

来自dyp发布的评论中的代码; Is there a cast (or standard function) with the opposite effect to std::move?,以下代码段编译。

我不确定代码是否有用,在linked post中讨论了这是否是一个好主意。

struct A {
    A() = default;
    A(A const&) = default; // copyable
    A& operator=(A const&) = default; // assignable
    A(A &&) = delete; // not movable
    A& operator=(A &&) = delete; // not movable
    ~A() = default;
};

template <typename T>
T& as_lvalue_ref(T&& t) {
    return t;
}

A foo() {
     A a;
     return as_lvalue_ref(a);
}

int main() {
    A a(as_lvalue_ref(foo()));
    return 0;
}

代码示例here

static_cast<T&>()代替as_lvalue_ref()也可以起作用,甚至可能更好(尽管看起来很笨拙),因为它实际上是冗长的。在返回引用的任何情况下,都可能发生悬空引用。在这种情况下给出签名A foo()(而不是说A& foo()),这里没有悬空引用,返回了A的完整对象。行A a(as_lvalue(foo()));没有悬空引用,因为从as_lvalue_ref(foo())返回的临时(prvalue)在表达式结束前保持有效(;),然后a对象将然后形成良好。

答案 1 :(得分:0)

有人带着那段代码来到另一个论坛。它不应该导致潜在的悬挂引用,这可能是Niall代码的情况。但是对于在C ++ 03中合法的东西仍然令人费解。

#include <iostream>
#include <functional>

struct A {
    A() =default;
    A(A const& a)=default;
    A& operator=(A const& a)=default;
    A(A &&) = delete; // not movable
    A& operator=(A &&) = delete; // not movable
    ~A()=default;
    int n;
};

A foo(void) {
    A a;
    a.n=5;
    std::cout<<"&a="<<&a<<std::endl;
    return std::cref(a); // A(A const&)
    // ~A()
}

int main(void) {
    A b; // A()
    std::cout<<"&b="<<&b<<std::endl;
    A const& const_ref_to_temp=foo(); // OK in C++
    b= const_ref_to_temp; //A=A const& [OK]
    std::cout<< b.n<<std::endl;
    return 0;
}