简体   繁体   English

如何使std :: vector类型安全

[英]How to make a std::vector type-safe

I have an obect called an IndexSet, currently defined as a std::vector, that I want to define as a separate type. 我有一个称为IndexSet的对象,当前定义为std :: vector,我想将其定义为单独的类型。

I want to be able to interact with it just as though it were a vector, but I also want type protection so that I don't accidentally use a "normal" vector when I want to use an IndexSet. 我希望能够像它是一个向量一样与它进行交互,但是我也想要类型保护,以便在使用IndexSet时不会意外地使用“正常”向量。

I have been able to come up with three options for how to do this, none of which please me. 我已经能够提出三种选择方法,但没有一个能让我满意。 I am hoping that there is a fourth that I am missing. 我希望我还缺四分之一。

Option #1: typdef 选项#1:typdef

typdef vector<int> IndexSet

This allows me to use an IndexSet exactly as I would a vector, but it gives me zero type protection. 这使我可以像使用向量一样完全使用IndexSet,但是它为我提供了零类型保护。 I am able to pass a vector into a function expecting an IndexSet with zero complaints. 我能够将向量传递到期望带有零投诉的IndexSet的函数中。

Option #2: Public Wrapper Class 选项2:公共包装程序类

class IndexSet
{
public:
  vector<int> indexes;
};

This will give me type protection, but it requires me to use a level of indirection interacting with it. 这将为我提供类型保护,但它要求我使用与之交互的间接级别。 Instead of saying set.push_back(1); 不用说set.push_back(1); I have to say set.indexes.push_back(1); 我不得不说set.indexes.push_back(1);

Option #3: Private Wrapper Class 选项3:私人包装课程

class IndexSet
{
public:
  push_back....
  operator[]...
  etc...
private:
  vector<int> indexes
};

This will give me both type protection and allow me to interact directly with the IndexSet as though it were a vector, but ONLY if I first create wrapper methods for every single method of std::vector that I want to use with my IndexSet. 这将为我提供类型保护,并让我可以直接与IndexSet进行交互,就好像它是一个向量一样,但是仅当我首先为要与我的IndexSet一起使用的std :: vector的每个单个方法创建包装器方法时,才可以。

Of course, what I'd really like to do is to just create a new class that inherits from vector but has zero implementation of its own, but I know that the standard library containers do not like to be inherited from. 当然,我真正想做的只是创建一个新的类,该类从vector继承,但自己的实现为零,但是我知道标准库容器不喜欢从那里继承。

Are there any other options that I'm missing? 我还有其他选择吗?

Is there some functionality that differs between an IndexSet and a vector? IndexSet和向量之间是否有某些功能不同? Is there some difference in how these objects are used? 这些对象的使用方式是否有些不同? If the answer is no, then why do you want to do this? 如果答案是否定的,那么为什么要这样做呢?

Your typedef does not suffice only if there is something intrinsically wrong with supplying a std::vector<int> to a functions that expects an IndexSet . 仅当将std::vector<int>给需要IndexSet的函数时,您的typedef并不足够。 That would suggest that an IndexSet does not satisfy an is-a relationship with respect to std::vector<int> . 这将暗示IndexSet不满足于std::vector<int>的is-a关系。 That in turn means that even if you could public inheritance, you shouldn't be doing so. 反过来,这意味着即使您可以公开继承,也不应这样做。

If the relationship is implemented-by rather than is-a, this suggests using either containment or private (and possibly protected) inheritance. 如果关系是通过-而不是通过-a实现的,则建议使用包含继承或私有(并且可能是受保护的)继承。 This is much safer than public inheritance from a container class because programmers who use your class have to go out of their way to get a base class pointer. 这比从容器类公开继承要安全得多,因为使用您的类的程序员必须不遗余力地获取基类指针。 (The way to do it is to use a C-style cast. C-style casts can convert a derived type to a parent class even if the inheritance is not public.) (这样做的方法是使用C样式强制转换。即使继承不是公共的,C样式强制转换也可以将派生类型转换为父类。)

The advantage of using private inheritance in instead of containment in this case is that you can easily promote selected inherited member functions from private to protected via the using statement. 在这种情况下 ,使用私有继承而不是包含的优点是,您可以通过using语句轻松地将选定的继承成员函数从private提升为protected。 You would have to write a bunch of wrapper functions if you used containment. 如果您使用遏制,则必须编写一堆包装函数。

class IndexSet : private std::vector<int> {
public:
   // Bunch of constructors, elided.

   using std::vector<int>::push_back;
   using std::vector<int>::operator[];
   using std::vector<int>::cherry_picking_of_only_the_stuff_you_want;
};

Update 更新资料

There are some non-member functions associated with std::vector , specifically comparison operators and std::swap . 有一些与std::vector相关的非成员函数,特别是比较运算符和std::swap Making comparable versions for your IndexSet will require wrapper functions, but there aren't that many (six comparison operators plus std::swap ), and you only need these if that functionality makes sense for this class. IndexSet可比较的版本将需要包装函数,但数量不多(六个比较运算符加上std::swap ),并且只有在该功能对该类有意义的情况下才需要这些。

Let's face it, one solution has all the advantages and just one disadvantage. 让我们面对现实,一种解决方案既有优点,也有缺点。

If you subclass std::vector, you just have to make sure you don't mix pointers to std::vector and your class, so nobody will delete a pointer to std::vector when it is actually of your subclass. 如果您将std :: vector子类化,则只需确保不要将指向std :: vector的指针和您的类混合使用,这样,当std :: vector实际上是您的子类的指针时,没有人会删除它。

Whether this is feasible depends on your project. 这是否可行取决于您的项目。 If this is an object that will be used by alot of people, in a public library, an OSS project etc, you might be safer wrapping it, else just subclass std::vector . 如果这是一个将由许多人使用的对象,则在公共图书馆,OSS项目等中,您可能会更安全地包装它,否则只需子类std::vector You'll be fine. 你会没事的。

Don't forget to add a comment at your class interface explaining the dangers. 不要忘记在您的类界面上添加注释以说明危险。 And you might be able do disable casting operators for extra safety (make your ctor explicit, ...). 而且,您可能可以禁用铸造操作员,以提高安全性(使您的ctor明确,...)。

This sounds like a job for.... BOOST_STRONG_TYPEDEF . 这听起来像是一项工作…… BOOST_STRONG_TYPEDEF http://www.boost.org/doc/libs/1_54_0/boost/serialization/strong_typedef.hpp http://www.boost.org/doc/libs/1_54_0/boost/serialization/strong_typedef.hpp

BOOST_STRONG_TYPEDEF(std::vector<int>, IndexSet)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM