Насколько глубокой должна быть копия (назначение) стертой карты

Я пишу библиотеку на C ++, для которой я реализовал обертку карты с типом стирания. Оболочка структурирована как в этой замечательной статье: http://www.cplusplus.com/forum/articles/18756/.

TLDR:

template<typename K, typename V>
class AnyMap
{
class MapConcept
{
public:
// Lots of pure virtual methods...
// These mimic the intersection of STL and Boost maps' interfaces
// Example:
virtual size_type size() = 0;
};

template<typename ActualMapType>
class MapModel : MapConcept
{
ActualMapType m;
public:
// Implementations of the parent's virtual methods...
// These basically just call the same method on member m.
// Example:
size_type size()  { return m.size(); }
};

MapConcept* mapConcept;

public:
// Again, the STL and Boost maps' interface methods
// Example:
size_type size()  { return mapConcept->size(); }
};

Я не уверен, представлю ли я эту карту как часть готовой библиотеки или уберу ее как вспомогательный класс, но в любом случае мне интересно, что делать с оператором присваивания.

В настоящее время у меня есть что-то вроде этого:

AnyMap& AnyMap::operator=(const AnyMap& other) {
delete mapConcept;
mapConcept = other.mapConcept->clone();
return *this;
}

Это означает, что если я создам две карты, скажем, карту STL и карту unordered_map в Boost, а затем назначу одну для другой, то теперь обе карты будут иметь один и тот же тип карты.

std::map<string, int> stlMap;
boost::unordered_map<string, int> boostMap;
// insert some stuff into maps
AnyMap<string, int> stlAnyMap( stlMap );
AnyMap<string, int> boostAnyMap( boostMap );

stlAnyMap = boostAnyMap;
// now stlAnyMap has a copy of boostMap

Таким образом, это имеет некоторый смысл, потому что содержание карты, назначенной для, является тем, что ожидается. Однако я подозреваю, что обычно типы карт будут отличаться одним из аргументов типа со значениями по умолчанию (например, Hash в Boost :: unordered_map). Так что, возможно, он должен сохранить базовый тип карты. Я думаю, это можно сделать с помощью чего-то вроде следующего:

AnyMap& AnyMap::operator=(const AnyMap& other) {
mapConcept->clear();
mapConcept->insert( other.mapConcept->begin(), other.mapConcept->end() );
return *this;
}

Это должно работать из-за шаблонного метода вставки:

template <class InputIterator>
void insert (InputIterator first, InputIterator last);

Кстати, если кому-то интересно, как я поступил с итераторами: я использовал any_iterator Томаса Беккера — http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html.

Так что вы думаете, ребята? Я склоняюсь к последнему подходу, но я хотел бы услышать любые аргументы для любой стороны.

Заранее спасибо!

РЕДАКТИРОВАТЬ: Вот первый аргумент против (возможно, вы могли бы сказать мне, насколько это важно): содержимое одного типа карты теперь может отображаться один в один на другую карту, если один предикат различает два ключа на карте, а другой считает их одинаковыми.

1

Решение

Вы хотите, чтобы оболочка карты имела семантику значений или нет? Это будет определять, насколько глубокой должна быть копия. В любом случае, реализация other.mapConcept->clone() будет полиморфным (это, в конце концов, суть техники стирания типа C ++) и приведет к диспетчеризации вызова в подклассе MapModel, который выглядит следующим образом

virtual MapModel *clone() { return new MapModel(m); } // covariant return type

Таким образом, все сводится к тому, что делает конструктор копирования ActualMapType (так как переменная-член m будет копия.)

Поскольку техника была изобретена для получения семантики значений, я думаю, что сохранение этой функции согласуется с принципом наименьшего сюрприза. Кроме того, дело в том, чтобы иметь фиксированный интерфейс. Реализация (STL или Boost или что-то еще) не имеет отношения к дизайну, поэтому нет смысла пытаться сохранить реализацию в любом конкретном экземпляре объекта.

Кстати, ваша реализация operator = для «стандартного» случая не является безопасной для исключения. Идея копирования и замены (возможно, с помощью специального метода swap ()) работает лучше

AnyMap( AnyMap const& other )
: mapConcept( other.mapConcept ? other.mapConcept->clone() : 0)
{}

AnyMap& operator= ( AnyMap rhs ) // note temporary: invokes copy constructor
{ std::swap( mapConcept, rhs.mapConcept ) ; return *this; }
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]