从 STL 容器继承并删除"新"运算符以防止由于缺少虚拟析构函数而导致未定义的行为是否有意义?

Does it make sense to inherit from STL containers and delete `new` operators to prevent undefined behavior because of lacking virtual destructors?

本文关键字:quot 析构函数 虚拟 未定义 于缺少 有意义 是否 继承 STL 删除 运算符      更新时间:2023-10-16

我在这个论坛上被告知,我在书中读过它,还有其他答案指出继承 STL 容器从来都不是好事,因为 STL 容器析构函数不是虚拟的(通过基类指针删除派生对象时未定义的行为)。

但是,C++11 标准现在允许在编译时使用成员函数说明符(如delete)进行按合同设计进行检查。我完全可以理解为什么继承一个 STL 容器,目标是用一个或两个成员函数进行扩展,最好将成员函数编码为算法。尽管如此,我还是遇到这样一种情况,即我将元素集合建模为概念,而元素本身是其他元素的容器。我需要实现访问子元素数据的双向迭代器 前向迭代器(例如 Collection::sub_element_iterator)。 在这种情况下,使用组合迫使我重新键入(适应)整个 std::vector 公共接口,只是为了使用迭代器扩展这个新集合。

在这种情况下,如果我仍然使用继承,并通过以下方式阻止堆分配,是否可以?

这是一个小模型:

#include <vector>
class not_heap_allocable
{
public: 
void* operator new  (std::size_t count) = delete;
};
template
<
typename Type,
template <typename T> class Allocator = std::allocator
>
class extended_vector
:
public std::vector<Type, Allocator<Type>>, 
public not_heap_allocable
{
public: 
typedef std::vector<Type> BaseType; 
using BaseType::BaseType; 
};
using namespace std;
int main(int argc, const char *argv[])
{
vector<int>* vNew = new extended_vector<int> ({0,1,2,3,4,5});  // Compile time error. 
return 0;
}

然后导致编译时错误:

main.cpp: In function ‘int main(int, const char**)’:
main.cpp:31:64: error: use of deleted function ‘static void* not_heap_allocable::operator new(std::size_t)’
vector<int>* vNew = new extended_vector<int> ({0,1,2,3,4,5});  // Compile time error. 
^
main.cpp:6:15: error: declared here
void* operator new  (std::size_t count) = delete;

因此,extended_vector不再指望人类不要滥用它。

这种方法似乎比继承protected然后using(公开)子类实际需要公开的基类成员更复杂,可能更不清楚。这样可以防止以这种方式公开继承的所有问题,同时不会通过探索新问题引入任何意想不到的问题。

编辑:我从boost中找到了我想要的东西:这个问题编写一个迭代器,使多个容器看起来像一个链接到boost::joinhttp://www.boost.org/doc/libs/1_46_1/libs/range/doc/html/range/reference/utilities/join.html,使您可以将多个范围合并为一个。

不,从不设计为具有派生的类派生是没有意义的。

实际上,您必须封装该类并将每个所需的功能转发给该封装的成员。

由于派生类仍然是一个基类,一旦它作为基类传递,你就会失去派生。

可以使用私有继承,但仍必须再次公开每个功能。