Как создать вектор с уникальными значениями?
У меня есть этот пример для генерации уникальных объектов в вектор:
#include <iostream>
#include <vector>
#include <algorithm>
int v=0;
struct A
{
A() : refValue( v++)
{ std::cout<<"constructor refValue="<<refValue<<std::endl; }
A( const A &r ) : refValue(r.refValue)
{ std::cout<<"copy constructor refValue="<<refValue<<std::endl; }
A& operator=( const A &r )
{
refValue = r.refValue;
std::cout<<"operator= refValue="<<refValue<<std::endl;
return *this;
}
~A() { std::cout<<"destructor refValue="<<refValue<<std::endl; }
int refValue;
};
A GenerateUnique()
{
A unique;
return unique;
}
struct B
{
B( const int n) : v()
{
std::generate_n( std::back_inserter( v ), n, &GenerateUnique );
}
std::vector< A > v;
};
int main()
{
B b(3);
}
Если я изменю свой основной на это:
struct B
{
B( const int n) : v(n)
{
}
std::vector< A > v;
};
тогда один объект типа A будет скопирован во все векторные элементы.
Есть ли способ создать вектор со всеми уникальными объектами (как в 1-м примере)?
Чтобы было понятнее: у меня есть класс, содержащий вектор. Этот вектор должен содержать все уникальные объекты (не копию одного объекта). И я хотел бы инициализировать его в списке инициализации (не в теле конструктора).
3 ответа
Ваша первая попытка - та, которая работает.
В действующем стандарте C++03 эта строка
std::vector< A > as( n );
явно определено, чтобы создать один A
возразить и скопировать это n
раз.
Я верю, что в C++0x это изменилось, чтобы создать n
построено по умолчанию A
с (небольшая разница). Тогда, возможно, вы сможете что-то сделать в A
Конструктор, чтобы сделать каждый экземпляр уникальным.
Прямо сейчас вы не можете.
Он копируется, потому что подпись этого конструктора выглядит следующим образом:
explicit vector( size_type count,
const T& value = T(),
const Allocator& alloc = Allocator());
Очевидно, что вы просто передаете конструктор по умолчанию этому конструктору, и он копирует его.
Если вы хотите инициализировать в списке инициализаторов, вы, очевидно, ограничены конструкторами некоторых объектов. Полагаю, вам не хотелось бы создавать класс-оболочку только для инициализации вектора в списке инициализаторов, так что мы ограничены конструкторами вектора. Единственное, что кажется разумным, это
template <class InputIterator>
vector( InputIterator first, InputIterator last,
const Allocator& alloc = Allocator() );
Таким образом, вы можете создать итератор, который будет возвращать необходимое количество построенных по умолчанию объектов.
Я предлагаю просто конструировать в теле конструктора, хотя.
Как уже говорилось, вы можете использовать make_function_input_iterator
от наддува следующим образом:
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/iterator/function_input_iterator.hpp>
// A && GenerateUnique the same ...
struct B
{
B( const int n) : v(boost::make_function_input_iterator(&GenerateUnique, 1), boost::make_function_input_iterator(&GenerateUnique, n))
{
}
std::vector< A > v;
};
int main()
{
B b(3);
}
Однако обратите внимание, что когда я тестировал код, я увидел, что происходит больше копирования / operator =, чем в вашем первом решении. Кроме того, также был создан дополнительный объект (refvalue 3) (для последнего итератора stop). Я не знаю, возможно ли это дополнительное поведение, но оно помогает при инициализации вектора в списке инициализаторов, если вы действительно этого хотите.