如何实现自己的函数到std :: vector?

时间:2011-06-15 17:10:47

标签: c++ std

我想添加一个函数,它将.size()值作为整数返回,而不是无符号整数。

编辑:由于评论,我解释得更详细:

我有代码:

int something = 3;
if(arr.size() > something) 

哪会产生编译器警告,我不喜欢添加(int)到我拥有它的每个地方。 所以,我认为使用sizei()函数会很好:

int something = 3;
if(arr.sizei() > something) 

哪个不会产生警告。

所以,我不想创建一个单独的函数,而是std :: vector本身的函数。

编辑:似乎唯一的方法就是创建另一个功能,例如:

template <typename T>
inline int sizei(const T &arr){
    return (int)arr.size();
}

从积极的方面来看:这根本不会增加我的可执行文件大小。

6 个答案:

答案 0 :(得分:6)

首先,你为什么要这样?我没有看到任何理由或优势:

无论如何,你可以这样做:

template<typename T>
int size(const std::vector<T> &v) { return (int) v.size(); }

//use
std::vector<int> ints;
//...
int count = size(ints);

我仍然没有看到这样做的任何意义。你可以简单地写一下:

int count = (int) ints.size(); 

但我仍然会说它并不比以下更好:

size_t count = ints.size(); //don't prefer anything over this. Always use size_t

建议:避免使用int大小。首选size_t


关于你问题的编辑。为什么不使用size_t作为:

size_t something = 3;
if(arr.size() > something) 

没有警告。在我看来,如果您在整个程序中一致地选择数据类型,那么当您要将intsize_t进行比较时,您就不会遇到这种情况,该int被定义为 unsigned 整数型。

或者,如果您有一些遗留代码要使用,并且使用int something = /*some legacy code API call or something */; if(arr.size() > (size_t) something) //or even better; size_t something = (size_t) /*some legacy code API call or something */; if(arr.size() > something) 作为大小,那么我认为在您需要时使用显式强制转换更好,而不是在框架本身隐藏了潜在的问题:

{{1}}

答案 1 :(得分:2)

通常,在C和C ++中,不应使用size_t等无符号类型来限制域。这是因为(1)这些语言不提供范围检查,(2)它们确实提供了不合理的隐式促销。没有范围检查意味着(1)没有优势,不合理的隐含促销意味着(2)非常不利的缺点,所以这是非常愚蠢的事情:没有优势,非常不利的缺点。

但是,这些语言的标准库可以做到这一点。他们只为历史原因做这件事,在早期决定中不可逆转地抓住了,这在某个时候是有意义的。这具有非常愚蠢的后果,例如C99需要ptrdiff_t的17(!)位,并且它具有上述非常不期望的后果,例如使用非常多的时间来搜寻由隐式促销(等)导致的错误。例如,在C ++中,你几乎可以保证std::string( "bah!" ).length() < -5 - 这很容易让你绊倒,无论如何都像设计一样愚蠢。

现在,您无法在std::vector中注入新的成员函数,但您可以添加一个独立的函数。一个好名字是countOf。模板使它可以应用于任何事物(原始数组,向量等)。

据我所知,函数的三元组startOfendOfcountOf首先由Dietmar Kuehl确定。 C ++ 0x将有std::beginstd::end,但AFAIK没有对应的std::size。在此期间,您可以定义此支持,它允许您处理任何类型的容器和原始数组相同。

一个示例实现&amp; my blog提供了进一步的讨论。


编辑添加一些代码,因为它已在评论中提出。

检测合适的迭代器类型:

template< typename Type >
struct It
{
    typedef typename Type::iterator T;
};

template< typename Type >
struct It< Type const >
{
    typedef typename Type::const_iterator T;
};

template< typename ElemType, Size N >
struct It< ElemType[N] >
{
    typedef ElemType* T;
};

countOfstartOfendOf函数,使用推导的迭代器类型:

template< typename T >
inline Size countOf( T const& c )           { return static_cast<Size>( c.size() ); }

template< typename T, Size N >
inline Size countOf( T (&)[N] )             { return N; }

template< typename T >
inline typename It<T>::T startOf( T& c )    { return c.begin(); }

template< typename T, Size N >
inline T* startOf( T (&a)[N] )              { return a; }

template< typename T >
inline typename It<T>::T endOf( T& c )      { return c.end(); }

template< typename T, Size N >
inline T* endOf( T (&a)[N] )                { return a + N; }

其中Sizeptrdiff_t的typedef。

注意:在64位Windows int(甚至long)中是32位。因此,对于非常大的数组,int通常是不够的。 ptrdiff_t保证能够表示任何两个指针之间的差异,当明确定义差异时。


干杯&amp;第h

答案 2 :(得分:1)

我倾向于使用显式强制转换为 int 而不是函数:static_cast<int> (v.size())。更好的是在处理内存大小时始终使用size_t。例如,支持for (size_t i=0; i < v.size(); ++i)而不是for (int i=0; i < (int) v.size(); ++i)。使用正确的类型进行工作。您不应该将std :: vector大小与签名类型进行比较。

请参阅以下参考资料,了解为什么您更喜欢size_t到int:

答案 3 :(得分:1)

您可以按照以下方式从向量派生:

template<typename T>
class my_vector : public vector<T>
{
  // missing constructors!

  int size() const
  {
    if (vector<T>::size() > INT_MAX)
      throw std::range_error("too many elements in vector");
    return (int) vector<T>::size();
  }
};

缺点是你必须自己定义和转发构造函数。

答案 4 :(得分:0)

.size()的快速回答是:不。对于向量,可能性是其存储值和alloc方法(默认new / delete,通常不会被覆盖)以及使用InputIterator的方法。

大多数人会问为什么你想要一个不同的size_t。如果它只是烦人的警告,你可以强制转换或使用无符号整数来对size()进行迭代/检查。 (如果它是很多代码,你将不得不寻找/替换)...如果它处理空条件,你可以将矢量包装在一个带有一些智能的类中。顺便说一句,因为我不知道你手头的问题,所以查找想法和已经实现的功能的好地方是std库的算法,例如sortfor_eachfind,等等。

对于std算法,请参阅:http://www.sgi.com/tech/stl/table_of_contents.html

答案 5 :(得分:0)

虽然@Nawaz在我看来提供了最恰当的答案,但如果你真的想在std :: vector&lt;&gt;中添加一个额外的成员这真的不可能。 @zvrba提供了唯一可以实现的方法,但正如评论中所述,std容器类型没有虚拟析构函数,因此不应该是子类。

但是,您可以使用容器适配器实现一种新类型的向量,如下所示:

template <class T>
class my_vector
{
public:
   int size_i() const
   {
      return static_cast<int>(container_.size());
   }

private:
   std::vector<T> container_;
};

这里的缺点是你必须明确地公开你实际需要支持的容器的功能。如果您在整个代码中正常使用'std :: vector',这可能是一个重大变化。有关容器适配器的实现示例,请参阅“std :: queue”。