编译器不会使用副本分配而是移动?

时间:2016-05-13 16:04:51

标签: c++ c++11 copy-assignment move-assignment-operator

我有一个类,其中移动赋值被显式删除,因为该对象不应该是可移动的。但是如果我使用RVO分配给这个类的实例,编译器会给我错误:

main.cpp:12:16: note: candidate function has been explicitly deleted

编译器也提到了现有的复制赋值运算符,但没有使用它。

这是我的代码(或(不)运行示例here):

class foo {
public:
    foo() {}
    foo(foo const& r) {}
    foo(foo&&) = delete;

    foo const& operator=(foo const& r) { return *this; }
    foo const& operator=(foo&& r) = delete;
};

int main(int argc, char **argv) {
    foo bar;
    bar = foo();
    return 0;
}

我找到了一篇非常相似的帖子here

我知道我可以通过暂时使用来避免这种情况。我想知道为什么每个编译器(我用gcc,clang和vs2013测试过)都不能直接调用现有的拷贝分配?有什么我想念的吗?

3 个答案:

答案 0 :(得分:3)

不会调用复制分配,因为(已删除的)移动分配更适合重载分辨。

根本不要声明移动任务。然后将选择复制分配。不会生成隐式移动赋值运算符,因为该类具有用户声明的复制构造函数,移动构造函数和复制赋值运算符。其中任何一个都会阻止生成隐式移动赋值运算符。

  

但是如果我使用RVO分配给这个类的实例

这里没有涉及RVO。您创建一个临时foo并将其复制分配给现有变量。无法省略复印作业。

此外,从赋值运算符返回值是非常不寻常和低效的。

答案 1 :(得分:1)

就像std::move()应用static_cast<>()来强制使用移动分配/构造器一样,可以做一些类似于强制使用拷贝分配/构造器的事情:

#include <iostream>

class foo
{
public:

    foo() {}
    foo(foo const& r) {}
    foo(foo&&) = delete;

    foo const& operator=(foo const& r) { std::cout << ":)\n"; return *this; }
    foo const& operator=(foo&& r) = delete;
};

int main(int argc, char **argv)
{
    foo bar;
    bar = static_cast<const foo&>(foo());
    return 0;
}

答案 2 :(得分:0)

您可以使用展示位置来执行此操作:

#include <iostream>
#include <string>
#include <new>

class foo {
public:

    foo() {}
    foo(foo const& r) {}
    foo(foo&&) = delete;

    foo const& operator=(foo const& r) { return *this; }
    foo const& operator=(foo&& r) = delete;
};

int main(int argc,char **argv)
{
    foo bar;

    //bar = foo();
    bar.~foo();
    new(&bar) foo();

    return 0;
}