2

我可以创建包含不可复制元素且在 C++11 中没有默认构造函数的向量吗?

例子:

#include <iostream>
#include <string>
#include <vector>

struct value {
    value() = delete;
    ~value() = default;

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

    explicit value(int i) : i_(i) {}
private:
    int i_;
};

int main() {
    std::vector<value> v;
    v.reserve(10);
    for (unsigned i = 0; i < 10; ++i)
        v.emplace_back(7);
}

在这里我想创建 10 个值,每个值 ctor 传递整数 7 ...

std::vector< value > v(in-place, 10, 7)

为什么没有将 C++11 放置构造形式添加到此 std::vector 构造函数中

从coliru粘贴的错误:

+ g++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp
In file included from /usr/include/c++/4.8/vector:62:0,
                 from main.cpp:3:
/usr/include/c++/4.8/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = value; _Args = {value}]’:
/usr/include/c++/4.8/bits/stl_uninitialized.h:75:53:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<value*> _ForwardIterator = value*; bool _TrivialValueTypes = false]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:117:41:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<value*> _ForwardIterator = value*]’
/usr/include/c++/4.8/bits/stl_uninitialized.h:258:63:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = std::move_iterator<value*> _ForwardIterator = value*; _Tp = value]’
/usr/include/c++/4.8/bits/stl_vector.h:1142:29:   required from ‘std::vector<_Tp, _Alloc>::pointer std::vector<_Tp, _Alloc>::_M_allocate_and_copy(std::vector<_Tp, _Alloc>::size_type, _ForwardIterator, _ForwardIterator) [with _ForwardIterator = std::move_iterator<value*> _Tp = value; _Alloc = std::allocator<value> std::vector<_Tp, _Alloc>::pointer = value*; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/usr/include/c++/4.8/bits/vector.tcc:75:70:   required from ‘void std::vector<_Tp, _Alloc>::reserve(std::vector<_Tp, _Alloc>::size_type) [with _Tp = value; _Alloc = std::allocator<value> std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
main.cpp:24:17:   required from here
/usr/include/c++/4.8/bits/stl_construct.h:75:7: error: use of deleted function ‘value::value(const value&)’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^
main.cpp:11:5: error: declared here
     value(value const&) = delete;
     ^
4

4 回答 4

3

出现错误的原因是使用emplace_backon astd::vector要求元素类型至少为MoveConstructible。如果向量需要增长并重新分配其元素,则需要这样做。

向您的结构添加一个移动构造函数,您将能够在您的代码中使用它(默认实现足以满足您的代码)。

value(value&&) = default;

编译器不会为您的结构隐式生成默认移动构造函数,因为您已经声明了自己的复制构造函数value(value const&) = delete=delete并且=default算作用户声明),以及复制赋值运算符析构函数

有关隐式移动构造函数生成规则的更多信息,请参见此处:为什么没有默认移动分配/移动构造函数?


使用std::vector形式的构造函数std::vector(size_t count, const T& value)将值复制到向量中,并要求元素类型为CopyConstructible

于 2013-07-30T13:10:11.747 回答
2

是的,如果您定义它(无论 cppreference 怎么说),都可以使用移动而不是复制构造函数/赋值来处理调整大小等。

#include <vector>
#include <iostream>

struct value {
    int i_;

    explicit value(int i) : i_(i)   {std::cout<<"value::value("  <<i_<<")\n"; }
    value(value &&src) : i_(src.i_) {std::cout<<"value::value(&&"<<i_<<")\n"; }
    value(value const&) = delete;
    value& operator=(value const&) = delete;
    value& operator=(value &&src) {
        i_ = src.i_;
        std::cout << "value::=(&&" << i_ << ")\n";
        return *this;
    }
    value() = delete;
};

int main() {
    std::vector<value> v;
    v.reserve(1);
    v.emplace_back(1);
    v.emplace_back(2);
    v.emplace_back(3);
}

工作正常:

value::value(1)   <-- emplace_back(1)
value::value(2) 
value::value(&&1) <-- emplace_back(2) inc. resize & move 1
value::value(3)
value::value(&&1)
value::value(&&2) <-- emplace_back(3) inc. resize & move 1,2

需求的动机

在移动支持之前,如果向量的元素是不可复制的,它将无法调整自身的大小(或删除项目,或完成相当多的界面)。

于 2013-07-30T12:33:42.590 回答
1

vector是的,如果它们是可移动的,您可以将不可复制或默认构造的对象放入 C++11 中:

#include <iostream>
#include <string>
#include <vector>

struct value {
    value() = delete;
    ~value() = default;

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

    // Move construction and assignment
    value(value&&) = default;
    value& operator =(value&&) = default;

    explicit value(int i) : i_(i) {}
private:
    int i_;
};

int main() {
    std::vector<value> v;
    v.reserve(10);
    for (unsigned i = 0; i < 10; ++i)
        v.emplace_back(7);
}

但是你不能使用用给定值的副本填充这样一个向量的构造函数——因为这些值是不可复制的。同样,您不能使用resize.

于 2013-07-30T13:01:14.540 回答
0

编写一个移动构造函数,然后使用emplace_back

struct value
{
    ...

    value(value && obj) : i_(obj.i_)
    {
    }

    or 

    value(value && obj) = default;

    ...
};

std::vector<value> v;

for (int i=0; i<10; i++)
   v.emplace_back(7);
于 2013-07-30T12:49:54.000 回答