我可以使用 reinterpret_cast 来销毁非动态分配的对象吗?
Can I use reinterpret_cast to destroy non dynamically allocated objects?
我做了一个很简单的vector实现。我承认我作弊了很多,唯一的实例变量是例如 size_t sz
和 T * elem
。许多问题之一(但这是我所知道的唯一可能导致崩溃的问题)是 pop_back()
.
的问题
template <typename T>
void vec<T>::pop_back() {
if (sz == 0)
return;
elem[sz-1].~T();
--sz;
}
向量elem
是一个动态分配的数组,但数组中的对象可能是也可能不是。我在这里看到的问题是,如果我破坏了这个数组中的一个对象,这可能会崩溃。如果我多次销毁元素,就会发生这种情况。这么说吧,万一我用了pop_back。这似乎不会发生在我的编译器上(这看起来很奇怪),但我听说有人对这个函数有这个问题。我一直在尝试在网络上进行一些研究,并找到了另一个 alternative。这里没有做零检查(可能是懒惰),这个例子是使用reinterpret_cast
template<class T>
void Vector<T>::pop_back() {
// You way want to do a check for empty() before calling the destructor.
// Call the destructor.
(reinterpret_cast<T*>(buffer)[_size-1]).~T();
// It is usual to prefer the pre decrement (and pre increment).
--_size;
}
问题是,我真的可以使用 reinterpret_cast 来销毁向量 class 中的非动态分配对象吗?
编辑
根据要求,我将展示我的 push_back,我不确定如何在我可以花在这上面的短时间内正确地写。我承认 class 的主要目的不是效率,而是一种处理资源而不是原始动态数组的好方法(我当然可以使用向量,但这是一个比一般策略更小范围的问题所以如果省略 use-std::vector 讨论,我将不胜感激)
template <typename T>
void vec<T>::push_back(const T& obj) {
T* tmp = new T[sz+1];
if (sz > 0){
uninitialized_copy(elem, elem+sz, tmp);
delete[] elem;
}
elem = tmp;
elem[sz] = T{obj};
++sz;
}
主要问题是容量。我意识到容量部分需要大量工作,否则我只能创建新元素。
这个答案的灵感来自于 Herb Sutter Exceptional C++ 一书中的堆栈实现(第 12 项):
如果用
初始化 T * elem
变量,则可以为 vec
分配内存
elem = static_cast<T*>(sz == 0 ? nullptr : operator new(sizeof(T)*sz));
这将为您提供尚未构造对象的内存。
编辑(感谢 Cheers 和 hth.-Alf):您还可以通过调用 a.allocate(sz)
.[=21= 使用分配器而不是上面的代码]
如果要向向量中添加新元素,可以使用construct
[1]. To call the destructor of an object you can use destroy
[2].
如果您现在跟踪变量 used
中向量中分配了多少元素,您可以通过调用 destroy(elem+used);
释放最后一个元素
construct
和 destroy
在它们内部使用新的放置和显式的析构函数调用。我建议使用这些函数而不是原始放置消息和析构函数调用。
我做了一个很简单的vector实现。我承认我作弊了很多,唯一的实例变量是例如 size_t sz
和 T * elem
。许多问题之一(但这是我所知道的唯一可能导致崩溃的问题)是 pop_back()
.
template <typename T>
void vec<T>::pop_back() {
if (sz == 0)
return;
elem[sz-1].~T();
--sz;
}
向量elem
是一个动态分配的数组,但数组中的对象可能是也可能不是。我在这里看到的问题是,如果我破坏了这个数组中的一个对象,这可能会崩溃。如果我多次销毁元素,就会发生这种情况。这么说吧,万一我用了pop_back。这似乎不会发生在我的编译器上(这看起来很奇怪),但我听说有人对这个函数有这个问题。我一直在尝试在网络上进行一些研究,并找到了另一个 alternative。这里没有做零检查(可能是懒惰),这个例子是使用reinterpret_cast
template<class T>
void Vector<T>::pop_back() {
// You way want to do a check for empty() before calling the destructor.
// Call the destructor.
(reinterpret_cast<T*>(buffer)[_size-1]).~T();
// It is usual to prefer the pre decrement (and pre increment).
--_size;
}
问题是,我真的可以使用 reinterpret_cast 来销毁向量 class 中的非动态分配对象吗?
编辑
根据要求,我将展示我的 push_back,我不确定如何在我可以花在这上面的短时间内正确地写。我承认 class 的主要目的不是效率,而是一种处理资源而不是原始动态数组的好方法(我当然可以使用向量,但这是一个比一般策略更小范围的问题所以如果省略 use-std::vector 讨论,我将不胜感激)
template <typename T>
void vec<T>::push_back(const T& obj) {
T* tmp = new T[sz+1];
if (sz > 0){
uninitialized_copy(elem, elem+sz, tmp);
delete[] elem;
}
elem = tmp;
elem[sz] = T{obj};
++sz;
}
主要问题是容量。我意识到容量部分需要大量工作,否则我只能创建新元素。
这个答案的灵感来自于 Herb Sutter Exceptional C++ 一书中的堆栈实现(第 12 项):
如果用
初始化T * elem
变量,则可以为 vec
分配内存
elem = static_cast<T*>(sz == 0 ? nullptr : operator new(sizeof(T)*sz));
这将为您提供尚未构造对象的内存。
编辑(感谢 Cheers 和 hth.-Alf):您还可以通过调用 a.allocate(sz)
.[=21= 使用分配器而不是上面的代码]
如果要向向量中添加新元素,可以使用construct
[1]. To call the destructor of an object you can use destroy
[2].
如果您现在跟踪变量 used
中向量中分配了多少元素,您可以通过调用 destroy(elem+used);
construct
和 destroy
在它们内部使用新的放置和显式的析构函数调用。我建议使用这些函数而不是原始放置消息和析构函数调用。