C++11 显式请求默认移动构造函数不起作用?

C++11 显式请求默认移动构造函数不起作用?,c++11,C++11,这是我的密码: #include <cstdint> #include <vector> class Bar { uint32_t m_value; public: Bar(const uint32_t value) : m_value(value) { } }; class Foo { Bar* m_p_bar; uint32_t m_value; Foo(const Foo&) = delete; F

这是我的密码:

#include <cstdint>
#include <vector>

class Bar {
    uint32_t m_value;
public:
    Bar(const uint32_t value) : m_value(value) {
    }
};

class Foo {
    Bar* m_p_bar;
    uint32_t m_value;
    Foo(const Foo&) = delete;
    Foo& operator=(const Foo&) = delete;
    Foo& operator=(Foo&&) = default;
    Foo(Foo&&) = default;
public:
    /*
    Foo(Foo&& from) {
        m_p_bar = from.m_p_bar;
        m_value = from.m_value;
        from.m_p_bar = nullptr;
    }
    */
    Foo(const uint32_t value) : m_value(value) {
        m_p_bar = new Bar(value);
    }
};

int main() {
    std::vector<Foo> foos;
    foos.emplace_back(8);
}
#包括
#包括
分类栏{
uint32μt mμ值;
公众:
条形图(常数32_t值):m_值(值){
}
};
福班{
酒吧*m________;
uint32μt mμ值;
Foo(const Foo&)=删除;
Foo&运算符=(const Foo&)=删除;
Foo&operator=(Foo&&)=默认值;
Foo(Foo&&)=默认值;
公众:
/*
Foo(Foo&&from){
m_p_巴=从.m_p_巴;
m_值=from.m_值;
from.m_p_bar=nullptr;
}
*/
Foo(const uint32_t value):m_value(value){
m_p_条=新条(值);
}
};
int main(){
std::矢量foos;
后置炮台(8);
}
编译器抱怨:

In file included from /opt/rh/devtoolset-9/root/usr/include/c++/9/vector:66,
                 from test_implicit_func.cpp:2:
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/stl_uninitialized.h: In instantiation of ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<Foo*>; _ForwardIterator = Foo*]’:
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/stl_uninitialized.h:307:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<Foo*>; _ForwardIterator = Foo*; _Tp = Foo]’
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/stl_uninitialized.h:329:2:   required from ‘_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = Foo*; _ForwardIterator = Foo*; _Allocator = std::allocator<Foo>]’
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/vector.tcc:474:3:   required from ‘void std::vector<_Tp, _Alloc>::_M_realloc_insert(std::vector<_Tp, _Alloc>::iterator, _Args&& ...) [with _Args = {int}; _Tp = Foo; _Alloc = std::allocator<Foo>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<Foo*, std::vector<Foo> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = Foo*]’
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/vector.tcc:121:4:   required from ‘std::vector<_Tp, _Alloc>::reference std::vector<_Tp, _Alloc>::emplace_back(_Args&& ...) [with _Args = {int}; _Tp = Foo; _Alloc = std::allocator<Foo>; std::vector<_Tp, _Alloc>::reference = Foo&]’
test_implicit_func.cpp:34:21:   required from here
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/stl_uninitialized.h:127:72: error: static assertion failed: result type must be constructible from value type of input range
  127 |       static_assert(is_constructible<_ValueType2, decltype(*__first)>::value,
      |                                                                        ^~~~~
在/opt/rh/devtoolset-9/root/usr/include/c++/9/vector:66中包含的文件中,
从测试函数cpp:2:
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/stl_uninitialized.h:在“_forwarditeratorstd::uninitialized_copy”(_InputIterator,_InputIterator,_ForwardIterator,_ForwardIterator)[带_InputIterator=std::move_iterator;_ForwardIterator=Foo*]的实例化中:
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/stl_uninitialized.h:307:37:从“_forwarditeratorstd::_uninitialized_copy_a”(_inputierator,_inputierator,_ForwardIterator,std::allocator&)中需要(_inputierator=std::move_iterator;_ForwardIterator=Foo*;_Tp=Foo])
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/stl_未初始化。h:329:2:从“_forwarditeratorstd::_uninitialized_move_if_noexcept_a(_InputIterator,_InputIterator,_ForwardIterator,_Allocator&)[带_InputIterator=Foo*;_ForwardIterator=Foo*)_分配器=std::Allocator]”
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/vector.tcc:474:3:void std::vector::_M_realloc_insert(std::vector::iterator,_Args&&…[带_Args={int};_tpfoo;_Alloc=std::分配器;std::vector::iterator=u gnu cxx::u normal iterator;typename std:u vector:u vector基指针=Foo*]
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/vector.tcc:121:4:std::vector::reference std::vector::emplace_back(_Args&&…[带_Args={int};_Tp=Foo;_Alloc=std::分配器;std::vector::reference=Foo&])
测试函数cpp:34:21:此处为必填项
/opt/rh/devtoolset-9/root/usr/include/c++/9/bits/stl_未初始化。h:127:72:错误:静态断言失败:结果类型必须可以从输入范围的值类型构造
127 | static_assert(是可构造的::值,
|                                                                        ^~~~~
我注意到由于某种原因,我需要为
Foo
定义自己的移动构造函数。通过显式要求编译器使用默认构造函数(即
Foo(Foo&&)=default;
),它不起作用。但是,如果我要求编译器使用所有隐式构造函数(即删除
Foo(const Foo&))=delete;
Foo&operator=(const-Foo&)=delete;
Foo&operator=(Foo&&)=默认值;
Foo(Foo&&)=默认值;
),编译器不会抱怨


我的问题是,为什么显式要求编译器使用默认的move构造函数在这里不起作用,但它在这里起作用。这表明,如果它被隐式删除,我可以要求使用默认版本。

如果让编译器使用隐式定义的“big 5”,您将遇到泄漏和双自由:s的问题

您需要将move构造函数
设置为public
,并且需要
删除析构函数中的指针。您还需要确保指针不会留在moved from对象中

#包括//交换
福班{
酒吧*m________;
uint32μt mμ值;
公众:
Foo(const uint32_t值):
m_p__bar(新条(值)),
m_值(值)
{}
Foo(const Foo&)=删除;
Foo&运算符=(const Foo&)=删除;
Foo(Foo和rhs):
m_p_bar(std::exchange(rhs.m_p_bar,nullptr)),//在rhs中放置一个nullptr
m_值(rhs.m_值)
{}
Foo&operator=(Foo&rhs){
std::swap(m_p_-bar,rhs.m_-p_-bar);//让rhs破坏我们当前的酒吧
m_值=rhs.m_值;
归还*这个;
}
~Foo(){delete m\u p\u bar;}//销毁它
};

更好的办法是使用
std::unique\u ptr
-或者根本不使用指针。

啊,我没有注意到我隐式地将
Foo(Foo&&)=default;
设为私有。这就是问题所在。由于复制构造函数和复制赋值操作符被删除,我相信它们不必是私有的(我曾经在C++11之前将它们声明为私有而不进行实现,以便在任何代码试图复制时触发编译器错误)。如果我没有删除复制构造函数和复制赋值运算符,然后代码中的某个地方实际生成了一个副本,那么您提到的双重释放可能会发生,对吗?@HCSF我需要重述我的第一条评论。我的回答真的回答了您的问题吗?是的,当然。让我接受。只是对双重释放感到困惑frees@HCSF该做什么uble free:如果您确实在未正确管理指针的情况下启动
delete
ing,则s将进入。如果您让任何类型的
default
构造函数管理它,则两个对象将“拥有”它。
#include <utility> // exchange

class Foo {
    Bar* m_p_bar;
    uint32_t m_value;

public:
    Foo(const uint32_t value) : 
        m_p_bar(new Bar(value)),
        m_value(value) 
    {}

    Foo(const Foo&) = delete;
    Foo& operator=(const Foo&) = delete;

    Foo(Foo&& rhs) :
        m_p_bar(std::exchange(rhs.m_p_bar, nullptr)),  // put a nullptr in rhs
        m_value(rhs.m_value)
    {}
    Foo& operator=(Foo&& rhs) {
        std::swap(m_p_bar, rhs.m_p_bar);     // let rhs destroy our current Bar
        m_value = rhs.m_value;
        return *this;
    }

    ~Foo() { delete m_p_bar; }               // destroy it
};