Использует ли std::vector оператор присваивания своего типа значений для push_back элементов?
Если да, то почему? Почему он не использует конструктор копирования типа значения?
Я получаю следующую ошибку:
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/vector.tcc: In member functio
n `ClassWithoutAss& ClassWithoutAss::operator=(const ClassWithoutAss&)':
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/vector.tcc:238: instantiate
d from `void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterato
r<typename _Alloc::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp =
ClassWithoutAss, _Alloc = std::allocator<ClassWithoutAss>]'
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/stl_vector.h:564: instantia
ted from `void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = Class
WithoutAss, _Alloc = std::allocator<ClassWithoutAss>]'
main.cpp:13: instantiated from here
/usr/lib/gcc/i686-pc-cygwin/3.4.4/include/c++/bits/vector.tcc:238: error: non-st
atic const member `const int ClassWithoutAss::mem', can't use default assignment
operator
работает g++ main.cpp по следующему коду:
/*
* ClassWithoutAss.h
*
*/
#ifndef CLASSWITHOUTASS_H_
#define CLASSWITHOUTASS_H_
class ClassWithoutAss
{
public:
const int mem;
ClassWithoutAss(int mem):mem(mem){}
ClassWithoutAss(const ClassWithoutAss& tobeCopied):mem(tobeCopied.mem){}
~ClassWithoutAss(){}
};
#endif /* CLASSWITHOUTASS_H_ */
/*
* main.cpp
*
*/
#include "ClassWithoutAss.h"
#include <vector>
int main()
{
std::vector<ClassWithoutAss> vec;
ClassWithoutAss classWithoutAss(1);
(vec.push_back)(classWithoutAss);
return 0;
}
Ответы
Ответ 1
В стандарте С++ 03 говорится, что элементы должны быть пригодны для копирования и назначаться для копирования в стандартном контейнере. Таким образом, реализация может свободно использовать то, что она хочет.
В С++ 0x эти требования устанавливаются на основе операции. (В общем, элементы должны быть конструктивными и перемещаемыми по ходу.)
Чтобы получить то, что вы хотите, вы должны использовать умный указатель, такой как shared_ptr
(от Boost, TR1 или С++ 0x) и полностью отключить возможность копирования:
class ClassWithoutAss
{
public:
const int mem;
ClassWithoutAss(int mem):mem(mem){}
// don't explicitly declare empty destructors
private:
ClassWithoutAss(const ClassWithoutAss&); // not defined
ClassWithoutAss& operator=(const ClassWithoutAss&); // not defined
};
typedef shared_ptr<ClassWithoutAss> ptr_type;
std::vector<ptr_type> vec;
vec.push_back(ptr_type(new ClassWithoutAss(1)));
Указатели могут быть скопированы просто отлично, а интеллектуальный указатель гарантирует, что вы не просочитесь. В С++ 0x вы можете сделать это лучше всего с помощью std::unique_ptr
, используя преимущества move-semantics. (На самом деле вам не нужны общие семантики, но в С++ 03 это проще всего.)
Ответ 2
Проблема заключается в том, что типы в контейнере должны быть назначены.
Поскольку вы не определяете оператор присваивания для своего класса, компилятор будет генерировать его для вас. Оператор присваивания по умолчанию будет выглядеть следующим образом:
ClassWithoutAss& operator=(ClassWithoutAss const& rhs)
{
mem = copy.mem;
return *this;
}
// The compiler generated assignemtn operator will copy all members
// using that members assignment operator.
В большинстве ситуаций это сработает. Но член mem является константой и, следовательно, невозможен. Поэтому компиляция завершится неудачно, когда попытается сгенерировать оператор присваивания.