Как создать вектор с уникальными значениями? - PullRequest
7 голосов
/ 28 июля 2011

У меня есть этот пример для генерации уникальных объектов в вектор:

#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 будет скопирован во все векторные элементы.

Есть ли способ создать вектор со всеми уникальными объектами (как в первом примере)?

Чтобы было понятнее: у меня есть класс, содержащий вектор. Этот вектор должен содержать все уникальные объекты (не копию одного объекта). И я хотел бы инициализировать его в списке инициализации (не в теле конструктора).

Ответы [ 3 ]

3 голосов
/ 28 июля 2011

Ваша первая попытка - это то, что работает.

В текущем стандарте C ++ 03 эта строка

std::vector< A > as( n ); 

явно определена для создания одного A объекта и копирования этого n раз.

Я верю, что в C ++ 0x это изменилось, чтобы создать n сконструированных по умолчанию A s (небольшая разница).Тогда вы, возможно, сможете сделать что-то в конструкторе A, чтобы сделать каждый экземпляр уникальным.

Сейчас вы не можете.

3 голосов
/ 28 июля 2011

Копируется, потому что подпись этого конструктора выглядит следующим образом:

​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() );

Таким образом, вы можете создать итератор, который будет возвращать необходимое количество построенных по умолчанию объектов.1011 *

1 голос
/ 28 июля 2011

Как уже отмечалось, вы можете использовать make_function_input_iterator от boost следующим образом:

#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). Я не знаю, возможно ли такое дополнительное поведение, но оно помогает при инициализации вектора в списке инициализаторов, если вы действительно этого хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...