c++ - 类型删除映射的拷贝(分配)应该有多深

标签 c++ dictionary copy type-erasure

我正在用 C++ 编写一个库,为此我实现了一个带有类型删除的映射包装器。包装器的结构与这篇精彩文章中的一样:http://www.cplusplus.com/forum/articles/18756/ .

简单描述:

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 的贴图和一个 Boost 的 unordered_map,然后将一个贴图分配给另一个贴图,那么它们现在将具有相同的贴图类型。

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

所以,这是有道理的,因为分配给 map 的内容是预期的内容。但是,我怀疑通常映射类型会因具有默认值的类型参数之一而不同(例如 Boost::unordered_map 中的 Hash)。所以,也许它应该保留底层 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);

顺便说一下,如果有人想知道我是如何处理迭代器的:我使用了 Thomas Becker 的 any_iterator - http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html .

那么,大家怎么看呢?我倾向于后一种方法,但我想听听任何一方的论点。

提前致谢!

编辑:这是反对的第一个论点(也许,你可以告诉我这有多重要):如果一个谓词区分映射中的两个键,一个映射类型的内容现在可能一对一映射到另一个映射而另一个认为它们相同。

最佳答案

您是否希望 map 包装器具有值语义?这将决定拷贝的深度。在任何情况下,other.mapConcept->clone() 的实现都将是多态的(毕竟这是 C++ 类型删除技术的本质)并导致调度到调用看起来像这样的 MapModel 子类

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

所以一切都归结为 ActualMapType 的复制构造函数所做的事情(因为成员变量 m 将是一个拷贝。)

由于该技术是为获取值语义而发明的,因此我认为保留该功能符合 Least Surprise 原则。此外,关键是要有一个固定的接口(interface)。实现(STL 或 boost 或其他)与设计无关,因此尝试在任何特定对象实例中保留实现毫无意义。

顺便说一句,您对“标准”情况下的 operator= 的实现不是异常安全的。 copy-and-swap 习惯用法(也许使用自定义 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; }

关于c++ - 类型删除映射的拷贝(分配)应该有多深,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14297781/

相关文章:

r - 在 map 上绘制线条 - gcIntermediate

java - 两个相同的程序,只有一个可以编译(java7)

c++ - GDB 断点在 asio socket->connect 调用后停止工作

c++ - 加载 SMFL 共享库时出错

C++静态变量多实例

c++ - C++17 中包含 XPM 图像时发出警告

c++:我可以在不知道它是映射还是 vector 的情况下处理 std::_Container_base 吗?

dictionary - 在 Coq 8.6 中使用 FMap 的正确方法?

C++ 如何为基类转换对象调用纯虚拟方法?

ios - xcode 4 仅在设备上复制一次资源