std :: vector <object> reserve方法是否需要Object类的复制构造函数?</object>

时间:2014-01-27 15:36:29

标签: c++ c++11 vector

我正在尝试将一些点保留到std :: vector中,并且出现错误我不明白:

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

using namespace std;

class Foo{
public:    
    std::string str;
    int i;

    Foo(){
        this->str = "";
        this->i = 0;
    }

    Foo(Foo &copyFoo){
        this->str = copyFoo.str; //Or get methods if private members
        this->i = copyFoo.i;
    }

    Foo(std::string str, int i){
        this->str = str;
        this->i = i;
    }
};

int main()
{
   std::vector<Foo> fooVector;
   fooVector.reserve(20); // Error

   for(int i=0; i<20; i++){
       fooVector[i] = Foo("Test", i); // Or should I use operator new?
       // Or should I even stick to the push_back method?
   }

   return 0;
}

当然我可以不保留,它可能会起作用。但现在我对它为什么现在不起作用感兴趣。我添加了复制构造函数,因为它看起来可能是我当时遇到的问题。但是在添加了复制构造函数之后,它也无法正常工作。

错误说:

  

来自

的文件      

/usr/local/gcc-4.8.1/include/c ++ / 4.8.1 /载体:62:0,

             from main.cpp:3: /usr/local/gcc-4.8.1/include/c++/4.8.1/bits/stl_construct.h: In
     

实例化'void std :: _ Construct(_T1 *,_ Args&amp;&amp; ...)[with _T1 =

     

富; _Args = {Foo}]':

     

/usr/local/gcc-4.8.1/include/c ++ / 4.8.1 /比特/ stl_uninitialized.h:75:53:

     需要来自'static _ForwardIterator

     

std :: __ uninitialized_copy&lt; TrivialValueTypes&gt; :: _uninit_copy(_InputIterator,_InputIterator,_ForwardIterator)[with _InputIterator = std :: move_iterator; _ForwardIterator = Foo *;布尔

     

_TrivialValueTypes = false]'/usr/local/gcc-4.8.1/include/c ++ / 4.8.1 / bits / stl_uninitialized.h:117:41:

     '_ForwardIterator

需要

     

std :: uninitialized_copy(_InputIterator,_InputIterator,

     

_ForwardIterator)[with _InputIterator = std :: move_iterator; _ForwardIterator = Foo *]'/usr/local/gcc-4.8.1/include/c ++ / 4.8.1 / bits / stl_uninitialized.h:258:63:

     '_ForwardIterator

需要

     

std :: __ uninitialized_copy_a(_InputIterator,_InputIterator,

     

_ForwardIterator,std :: allocator&lt; _Tp&gt;&amp;)[with _InputIterator = std :: move_iterator; _ForwardIterator = Foo *; _Tp = Foo]'

     

/usr/local/gcc-4.8.1/include/c ++ / 4.8.1 / bits / stl_vector.h:1142:29:

     

需要'std :: vector&lt; _Tp,_Alloc&gt; ::指针std :: vector&lt; _Tp,

     

_Alloc&gt; :: _ M_allocate_and_copy(std :: vector&lt; _Tp,_Alloc&gt; :: size_type,_ForwardIterator,_ForwardIterator)[with _ForwardIterator = std :: move_iterator; _Tp = Foo; _Alloc = std :: allocator;

     

std :: vector&lt; _Tp,_Alloc&gt; :: pointer = Foo *;的std ::矢量&lt; _TP,

     

_Alloc&gt; :: size_type = long unsigned int]'/usr/local/gcc-4.8.1/include/c++/4.8.1/bits/vector.tcc:75:70:

     

要求'void std :: vector&lt; _Tp,_Alloc&gt; :: reserve(std :: vector&lt; _Tp,

     

_Alloc&gt; :: size_type)[with _Tp = Foo; _Alloc = std :: allocator; std :: vector&lt; _Tp,_Alloc&gt; :: size_type = long unsigned int]'

     

main.cpp:31:24:从这里要求

     

/usr/local/gcc-4.8.1/include/c ++ / 4.8.1 /比特/ stl_construct.h:75:7:

     

错误:没有匹配函数来调用'Foo :: Foo(Foo)'

 { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }

   ^ /usr/local/gcc-4.8.1/include/c++/4.8.1/bits/stl_construct.h:75:7:
     

注意:候选人是:main.cpp:22:5:注意:Foo :: Foo(std :: string,int)

 Foo(std::string str, int i){

 ^ main.cpp:22:5: note:   candidate expects 2 arguments, 1 provided main.cpp:17:5: note: Foo::Foo(Foo&)

 Foo(Foo &copyFoo){

 ^ main.cpp:17:5: note:   no known conversion for argument 1 from 'Foo' to 'Foo&' main.cpp:12:5: note: Foo::Foo()

 Foo(){

 ^ main.cpp:12:5: note:   candidate expects 0 arguments, 1 provided

问题出在哪里?我是否需要初始化std:vector对象,或者只是将每个位置分配给对象实例?

编辑:我正在使用C ++ 11。如果我删除了复制构造函数,我在保留方法行中收到以下错误:

required from 'void std::_Construct(_T1*, _Args&& ---) [with _TI = Foo; _Args = {Foo&}]

这就是我首先编写复制构造函数的原因。

我不想使用resize方法,因为我希望size方法返回包含在向量中的实际Foo对象数,而不是我保留的数量。

4 个答案:

答案 0 :(得分:6)

   std::vector<Foo> fooVector;
   fooVector.reserve(20); // Error

   for(int i=0; i<20; i++){
       fooVector[i] = Foo("Test", i); // Or should I use operator new?
       // Or should I even stick to the push_back method?
   }

上面的代码是错误的。您正在访问容器中size()之外的元素。这样做的惯用方法是在容器上执行push_back / emplace_back来实际创建对象,而不仅仅是内存:

   for(int i=0; i<20; i++){
       fooVector.emplace_back("Test", i);  // Alternatively 'push_back'
   }

除此之外,在C ++ 11中,容器中使用的类型需要复制或移动构造函数。

答案 1 :(得分:4)

更改

Foo(Foo &copyFoo) // bah!!! This can't make copies from temporaries

Foo(const Foo &copyFoo)  // now that's one good-looking copy constructor

答案 2 :(得分:1)

第一个问题是你的拷贝构造函数通过非const引用来获取它的参数,这会阻止从临时文件中复制。

在这种情况下,根本不需要声明复制构造函数:如果不这样做,那么将隐式定义一个复制每个成员,这就是你想要的。

如果类太复杂而不需要非默认的复制构造函数,那么它应该是

Foo(Foo const &);

请注意,您不一定需要复制构造函数来在vector中存储类型;如果你不希望你的类可以复制,那么移动构造函数就足够了。

第二个问题是您正在访问矢量的未初始化元素。 reserve只是在没有初始化的情况下为这么多元素保留记忆;您需要先插入元素(包括resizeinsertpush_backemplace_back或其他内容,然后才能访问它们。

答案 3 :(得分:0)

正如Luchian Grigore中的his answer所述,首先应修复您的复制构造函数。或者只是删除它,因为默认的一个就可以了。其次,要使用现有代码,您应该使用resize代替reserve

std::vector<Foo> fooVector;
fooVector.resize(20);

后者仅保留内存,但容器的大小保持不变 - 在您的情况下为0,因此访问元素是非法的。另一方面,resize做你想要的。

但总的来说,你甚至不应该这样做(例如here所述)。只需在空向量上使用push_backemplace_back即可为其填充内容。 resize将为您想要覆盖的每个元素调用默认构造函数。