我需要C++向量的最大大小(我给出的值)

I need the max size of my vector (the value I gave) C++

本文关键字:C++ 向量      更新时间:2023-10-16

我有以下代码:

固定大小的矢量:

template <typename T, size_t siz>
struct fixVec : public std::vector<T> {
void push_back(const T& d) {
if (std::vector<T>::size() >= siz) throw std::bad_alloc();
std::vector<T>::push_back(d);
}
};

我像这样使用"fixVec":

ClonableHeteroStore<ClonableTestClass, fixVec<ClonableTestClass*, 1>, MyException> t1;

它创建一个大小为 1 的向量。(1)

EXPECT_NO_THROW(t1.add(new ClonableTestClass));

它添加了 1 个元素,它很好,没有错误。(二)

EXPECT_THROW(t1.add(new ClonableTestClass), MyException);

在这里它应该抛出异常。(三)

我的问题是:我如何检查何时到达 MY 向量的"max_size()"。不是我的电脑可以处理的矢量的最大大小。 或者我怎样才能找回我在代码(1)中给出的值(!

ClonableHeteroStore<ClonableTestClass, fixVec<ClonableTestClass*, !!!1!!! >, MyException> t1;

我有一个名为 ClonableHeteroStore 的类,其中有以下代码:

template <typename T1, class S, typename PRED = int>
class ClonableHeteroStore 
{
private:
S flakker;
size_t currently;
size_t maxi;
public:
ClonableHeteroStore() :  { currently = 0; maxi = 0; }
void add(T1 *rhs)
{
if (currently < ???????? )
{
flakker.push_back(rhs);
currently++;
}
else
{
delete rhs;
throw PRED();
}
}

它应该做什么: 如果我们没有达到我们在代码(1)中给出的向量的最大大小,它应该向向量添加一个新元素。如果我们达到了代码(1)中给出的限制,它应该会删除异常。

所以第 (2)行不会有任何问题,因为向量的大小是 1,这是我们放入其中的第一个元素。"如果"部分应该运行。

(3)行将引发异常,因为它尝试放置第二个元素,但向量大小为1。"其他"部分应该运行。

唯一可以更改的代码是 ClonableHeteroStore 类。 不知何故,我应该找出,我的向量有多大。我读了很多向量动态分配它的大小等,但在这种情况下,如果我跳过限制 (1),它必须抛出异常。

感谢您的任何帮助!

从类型中提取模板参数的两种常见解决方案是使用部分显式专用化的类型特征或使用函数模板从函数参数推断模板参数的类型特征。基于函数的方法包括编写一个需要fixVec<T, I>的函数,并让编译器推导出I

// The compiler will deduce T and I from the argument
template<class T, size_t I>
size_t get_vec_size(const fixVec<T, I> &) {
return I;
}
void foo()
{
fixVec<char, 10> my_vec;
const auto my_vec_max_size = get_vec_size(my_vec);
}

要使用部分显式专用化,您可以编写一个新模板并将其专用化为您需要其模板参数的类型,并再次让编译器为您推断这些参数:

template<class T>
struct vec_size {};
template<class T, size_t I>
struct vec_size<fixVec<T, I>> : std::integral_constant<size_t, I> {};
void foo()
{
fixVec<char, 10> my_vec;
const auto my_vec_max_size = vec_size<decltype(my_vec)>::value;
}

有趣的问题!

例如,您可以使用模板模板参数:

template<template<typename, size_t> typename X, typename T, size_t N>
constexpr size_t get_size(const X<T, N>&) {
return N;
}
int main() {
std::cout << get_size(fixVec<int, 5>{}) << std::endl;
}

这不仅适用于fixVec,也适用于任何具有类型和size_t作为模板参数的模板类型!

因此,例如以下内容也是有效的:

get_size(std::array<int, 5>{});

固定大小的向量:

为什么对"固定"数组使用std::vector而不是std:array

它创建一个大小为 1 的向量。(1)

不,它没有。 它创建一个vector,其size()capacity()最初为 0,而不是 1。 您的siz值被用作人工最大容量,您仍然允许向量动态增长,直到达到最大值。

EXPECT_THROW(t1.add(new ClonableTestClass), MyException);

在这里它应该抛出异常。(三)

没错,更糟糕的是,它因此泄漏了ClonableTestClass对象。 您应该改用std::unique_ptr<ClonableTestClass>,以便始终保持对象的所有权并正确释放它,即使引发异常也是如此。

如何检查何时到达 MY 向量的"max_size()"。

你已经是了。 这正是size() >= siz正在做的事情。

或者我怎样才能找回我在代码 (1) 中给出的值(!

ClonableHeteroStore<ClonableTestClass, fixVec<ClonableTestClass*, !!!1!!! >, MyException> t1;

它仅在siz模板参数中可用。 如果你想让 OUTER 代码知道siz的值,那么你需要公开对它的公共访问,例如:

template <typename T, size_t siz>
struct fixVec : public std::vector<T>
{
const size_t max_elements_allowed;
fixVec() : max_elements_allowed(siz) {}
...
};

或者,如果您使用的是 C++11 或更高版本:

template <typename T, size_t siz>
struct fixVec : public std::vector<T>
{
const size_t max_elements_allowed = siz;
...
};

然后你可以这样做:

void add(T1 *rhs)
{
if (currently < flakker.max_elements_allowed)
{
flakker.push_back(rhs);
currently++;
}
else
{
delete rhs;
throw PRED();
}
}

仅供参考,您真的不需要currently,您可以改用flakker.size()

void add(T1 *rhs)
{
if (flakker.size() < flakker.max_elements_allowed)
{
flakker.push_back(rhs);
}
else
{
delete rhs;
throw PRED();
}
}

也就是说,std::vector有一个capacity()的方法,这正是您真正想要的:

void add(T1 *rhs)
{
if (flakker.size() < flakker.capacity())
{
flakker.push_back(rhs);
}
else
{
delete rhs;
throw PRED();
}
}

你只需要预先分配vector的内部数组:

template <typename T, size_t siz>
struct fixVec : public std::vector<T>
{
fixVec() { std::vector<T>::reserve(siz); } // <-- add this!
...
};

我有一个名为 ClonableHeteroStore 的类,其中有以下代码:

...

它应该做什么:如果我们没有达到我们在代码 (1) 中给出的向量的最大大小,它应该向向量添加一个新元素。如果我们达到了代码 (1) 中给出的限制,它应该删除一个异常。

由于您的fixVec已经在处理这个问题,因此您应该无条件地添加元素,并在需要时push_back()抛出:

void add(T1 *rhs)
{
try
{
flakker.push_back(rhs);
}
catch (...)
{
delete rhs;
throw PRED();
}
}

更好的设计是让调用方维护要添加的对象的所有权,除非add()成功,否则不要释放该所有权。 这样,如果引发异常,调用方可以正确释放对象,而不会泄漏它。 这不应该是add()的责任来处理:

void add(T1 *rhs)
{
try
{
flakker.push_back(rhs);
}
catch (...)
{
throw PRED();
}
}
...
ClonableTestClass *obj = new ClonableTestClass;
try
{
t1.add(obj);
}
catch (...)
{
delete obj;
throw;
}

或者,如果您使用的是 C++11 或更高版本:

std::unique_ptr<ClonableTestClass> obj(new ClonableTestClass);
t1.add(obj.get());
obj.release();

或:

void add(std::unique_ptr<T1> rhs)
{
try
{
flakker.push_back(rhs.get());
rhs.release();
}
catch (...)
{
throw PRED();
}
}
...
t1.add(std::unique_ptr<ClonableTestClass>(new ClonableTestClass));

唯一可以更改的代码是 ClonableHeteroStore 类。 不知何故,我应该找出,我的向量有多大。

如果你不能改变fixVec来公开它的siz值,你必须找出它的siz,那么你就必须诉诸一些模板技巧,例如:

template<typename T, size_t siz>
size_t get_capacity(const fixVec<T, siz> &) { return siz; }
...
void add(T1 *rhs)
{
if (flakker.size() < get_capacity(flakker))
flakker.push_back(rhs);
else
throw PRED();
}

但是,这正是 STL 容器公开标准size()capacity()方法的原因,因此您不必诉诸这样的技巧。

另一方面,ClonableHeteroStore实际上并不需要知道siz值。 它应该无条件地执行push_back(),并在需要时让它扔掉。

我读了很多向量动态分配它的大小等,但在这种情况下,如果我跳过限制 (1),它必须抛出异常。

你真的应该使用std::array而不是std::vector

如果必须使用std::vector,则应考虑编写自定义Allocatorvector使用,而不是使用默认Allocator。 如果要求自定义Allocator为太多元素分配内存,则可以抛出该。 然后,您可以让std::vector正常运行,而根本不覆盖其push_back()