我有以下代码:
固定大小的矢量:
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);
}
};
我使用&#34; fixVec&#34;像这样:
ClonableHeteroStore<ClonableTestClass, fixVec<ClonableTestClass*, 1>, MyException> t1;
它会创建一个大小为1的向量。 (1)
EXPECT_NO_THROW(t1.add(new ClonableTestClass));
它添加了1个元素,它很好,没有错误。的 (2)
EXPECT_THROW(t1.add(new ClonableTestClass), MyException);
这里应抛出异常。的 (3)
我的问题是:我怎样才能检查到达&#34; max_size()&#34;我的矢量。不是我的电脑可以处理的矢量的最大尺寸。 或者我怎样才能取回我在代码中提供的值 (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,这是我们放入其中的第一个元素。 &#34;如果&#34;部分应该运行。
行 (3) 会抛出异常,因为它会尝试放置第二个元素,但向量大小为 1 。 &#34;其他&#34;部分应该运行。
唯一可以更改的代码是ClonableHeteroStore类。不知怎的,我应该知道,我的矢量有多大。我读过很多矢量是在动态地分配它的大小等等,但是在这种情况下,如果我跳过限制(1),就必须抛出异常。
感谢您的帮助!
答案 0 :(得分:3)
从类型中提取模板参数的两种常见解决方案是使用部分显式特化的类型特征,或者使用函数模板从函数参数中推导出模板参数。基于函数的方法包括编写一个期望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;
}
答案 1 :(得分:1)
有趣的问题!
例如,您可以使用template template parameters:
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>{});
答案 2 :(得分:0)
固定大小的矢量:
为什么使用std::vector
代替std:array
来获取“固定”数组?
它创建一个大小为1的向量。(1)
不,它没有。它会创建vector
,其size()
和capacity()
最初为0,而不是1.您的siz
值被用作人工最大容量,你仍然允许矢量动态增长,直到达到你的最大值。
EXPECT_THROW(t1.add(new ClonableTestClass), MyException);
这里应抛出异常。 (3)
是的,更糟糕的是,它会泄漏ClonableTestClass
对象。您应该使用std::unique_ptr<ClonableTestClass>
代替,以便始终保持对象的所有权并正确释放它,即使抛出异常也是如此。
我如何检查何时到达MY矢量的“max_size()”。
你已经是。这正是size() >= siz
正在做的事情。
或者我怎样才能找回我在代码(1)中给出的值(数字之间的数字!):
ClonableHeteroStore<ClonableTestClass, fixVec<ClonableTestClass*, !!!1!!! >, MyException> t1;
仅适用于siz
模板参数。如果您希望OUTSIDE代码知道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
,那么您必须诉诸一些模板技巧,例如:< / p>
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()
,并在需要时让它抛出。
我读过很多矢量是dinamically分配它的大小等等,但在这种情况下,如果我跳过限制(1),它必须抛出异常。
您确实应该使用std::array
而不是std::vector
。
如果您必须使用std::vector
,则应考虑为Allocator
编写自定义vector
而不是使用默认Allocator
。如果要求为太多元素分配内存,则自定义Allocator
可以抛出。然后,您可以让std::vector
行为正常,而不是覆盖其push_back()
。