Преобразование между векторами с различными распределителями - PullRequest
9 голосов
/ 19 ноября 2011

Я написал простой тип распределителя с сохранением состояния в стиле C ++ 11.Учитывая

template<typename T> class my_allocator {
   // the usual stuff
};

template<typename T> using my_vector = std::vector<T, my_allocator<T>>;

my_vector<int> x;

std::vector<int> y = x; // error

Каков наилучший способ разрешить преобразования из my_vector в std::vector с использованием распределителя по умолчанию?GCC 4.7 (недавний svn) говорит:

error: conversion from 'my_vector<int> {aka std::vector<int, my_allocator<int>>}' to non-scalar type 'std::vector<int>' requested

Очевидно, что это можно сделать, скажем, с помощью простой функции преобразования, такой как

template<typename T> std::vector<T> to_std_vec(const my_vector<T>& v)  {
   return std::vector<T>(&v[0], &v[v.size()]);
   }

, но это выглядит довольнобезвкусный.Есть ли лучшее решение в C ++ 11?

Конечно, в этой ситуации семантика Move прямо не подходит, но я бы хотел, чтобы конструкция и назначение копирования работали без лишних шумов / печатания.

Ответы [ 3 ]

13 голосов
/ 19 ноября 2011

Вы не можете надеяться обойти очевидную копию: std::vector<int> y(x.begin(), x.end();. Элементы в y будут выделены std::allocator, а элементы в x были выделены и будут уничтожены вашим собственным распределителем. Два распределителя могут иметь совершенно не связанные понятия память и указатели ! Нет причин, по которым память, используемая одним распределителем, каким-либо образом связана с памятью другого.

Что еще можно сделать, кроме как скопировать семантический элемент?

Если вам больше не нужен старый контейнер, вы должны сделать move , однако:

std::vector<int> y(std::make_move_iterator(x.begin()),
                   std::make_move_iterator(x.end()));

(Это поможет в случае, если элементы имеют свой собственный распределитель, который согласен. Конечно, не для int.)

Обновление: Для подтверждения, обратите внимание, что внутренний буфер данных vector<T, Alloc> равен не типа T*, а скорее типа Alloc::pointer. Нет никакой причины, что это связанные типы для двух разных распределителей.

2 голосов
/ 15 января 2013

Есть 3 решения вашей проблемы:

I. Если ваш вектор 'y' еще не существует, вы можете использовать:

std::vector<int> y(x.begin(), x.end());

II. Если ваш вектор 'y' уже существует, вы можете использовать: (например, для члена класса)

this->y.assign(x.begin(), x.end());

Эти 2 способа заполнения вектора не ищут контейнертип.(и, следовательно, тип распределителя)

III. Другое решение заключается в создании родительского класса, который мог бы использоваться в качестве адаптера распределителя между распределителем std и вашим собственным распределителем.В этом случае ваши 2 распределителя имеют одинаковый тип и могут использоваться с векторными методами, такими как operator = ().

2 голосов
/ 19 ноября 2011

Хм, я думаю, что ваш единственный вариант здесь это полная копия, как:

std::vector<int> y( x.begin(), x.end());
...