当我尝试深度复制`unique_ptr`时出现segfault
getting a segfault when I try to deep copy `unique_ptr`s
为什么我不能从clone
函数返回unique_ptr
?我以为我能做到。
我有一个用于不同数学函数的基类,叫做transform
。我有一个指向这种类型的指针容器,因为我使用的是多态性。例如,所有这些派生类都有log_jacobian
的不同实现,这对统计算法很有用。
我将unique_ptr
s用于这个transform
类,因此我制作了一个(纯虚拟(clone
函数,使新的unique_ptr
指向同一数学transform
对象的深层副本。这个新对象的类型与从transform<float_t>
派生的对象的类型相同,但它是单独的,因为不能有两个unique_ptr
指向同一个对象。
template<typename float_t>
class transform{
...
virtual std::unique_ptr<transform<float_t>> clone() const = 0;
...
};
我的transform_container
课一次只上几个这样的课。毕竟,大多数统计模型都有不止一个参数。
template<typename float_t, size_t numelem>
class transform_container{
private:
using array_ptrs = std::array<std::unique_ptr<transform<float_t>>, numelem>;
array_ptrs m_ts;
unsigned m_add_idx;
...
auto get_transforms() const -> array_ptrs;
};
不过,我不知道为什么深度复制函数get_transforms
不起作用。它用于制作副本,并访问容器中的各个转换。当我运行一些测试时,我会出现segfault。如果我在gdb
中运行它,它会明确地"告诉"我这行在它坏了之后有一个注释。
template<typename float_t, size_t numelem>
auto transform_container<float_t,numelem>::get_transforms() const -> array_ptrs
{
array_ptrs deep_cpy;
for(size_t i = 0; i < numelem; ++i){
deep_cpy[i] = m_ts[i]->clone(); // this line
}
return deep_cpy;
}
我还尝试过将std::move
转换为deep_cpy[i]
并使用unique_ptr::reset
,但没有成功。
编辑:
这里还有一些其他相关的方法:向transform_container
添加转换的方法,以及单个transform
:的工厂方法
template<typename float_t>
std::unique_ptr<transform<float_t> > transform<float_t>::create(trans_type tt)
{
if(tt == trans_type::TT_null){
return std::unique_ptr<transform<float_t> >(new null_trans<float_t> );
}else if(tt == trans_type::TT_twice_fisher){
return std::unique_ptr<transform<float_t> >(new twice_fisher_trans<float_t> );
}else if(tt == trans_type::TT_logit){
return std::unique_ptr<transform<float_t> >(new logit_trans<float_t> );
}else if(tt == trans_type::TT_log){
return std::unique_ptr<transform<float_t> >(new log_trans<float_t> );
}else{
throw std::invalid_argument("that transform type was not accounted for");
}
}
template<typename float_t, size_t numelem>
void transform_container<float_t, numelem>::add_transform(trans_type tt)
{
m_ts[m_add_idx] = transform<float_t>::create(tt);
m_add_idx++;
}
在get_transforms()
中,您正在整个m_ts[]
数组上循环,在所有元素上调用clone()
,甚至是尚未由add_transform()
分配的元素!未分配的unique_ptr
s将持有一个nullptr
指针,通过nullptr
调用非静态类方法是未定义的行为。
最简单的修复方法是将get_transforms()
中的循环更改为使用m_add_idx
而不是numelem
:
template<typename float_t, size_t numelem>
auto transform_container<float_t,numelem>::get_transforms() const -> array_ptrs
{
array_ptrs deep_cpy;
for(size_t i = 0; i < m_add_idx; ++i){ // <-- here
deep_cpy[i] = m_ts[i]->clone();
}
return deep_cpy;
}
否则,您将不得不手动忽略任何nullptr
元素,例如:
template<typename float_t, size_t numelem>
auto transform_container<float_t,numelem>::get_transforms() const -> array_ptrs
{
array_ptrs deep_cpy;
for(size_t i = 0, j = 0; i < numelem; ++i){
if (m_ts[i]) {
deep_cpy[j++] = m_ts[i]->clone();
}
}
return deep_cpy;
}
无论哪种方式,您都应该更新add_transform()
以验证m_add_idx
不会超过numelem
:
template<typename float_t, size_t numelem>
void transform_container<float_t, numelem>::add_transform(trans_type tt)
{
if (m_add_idx >= numelem) throw std::length_error("cant add any more transforms"); // <-- here
m_ts[m_add_idx] = transform<float_t>::create(tt);
++m_add_idx;
}
也就是说,由于transform_container
可以分配可变数量的变换,我建议将transform_container
更改为使用std::vector
而不是std::array
,例如:
template<typename float_t>
class transform_container{
private:
using vector_ptrs = std::vector<std::unique_ptr<transform<float_t>>>;
vector_ptrs m_ts;
...
auto get_transforms() const -> vector_ptrs;
};
template<typename float_t>
auto transform_container<float_t>::get_transforms() const -> vector_ptrs
{
vector_ptrs deep_cpy;
deep_cpy.reserve(m_ts.size());
for(const auto &elem : m_ts){
deep_cpy.push_back(elem->clone());
}
return deep_cpy;
}
template<typename float_t>
std::unique_ptr<transform<float_t>> transform<float_t>::create(trans_type tt)
{
switch (tt) {
case trans_type::TT_null:
return std::make_unique<null_trans<float_t>>();
case trans_type::TT_twice_fisher:
return std::make_unique<twice_fisher_trans<float_t>>();
case trans_type::TT_logit:
return std::make_unique<logit_trans<float_t>>();
case trans_type::TT_log:
return std::make_unique<log_trans<float_t>>();
}
throw std::invalid_argument("that transform type was not accounted for");
}
template<typename float_t>
void transform_container<float_t>::add_transform(trans_type tt)
{
m_ts.push_back(transform<float_t>::create(tt));
}
- C++中带有List类的迭代器Segfault
- 使用Vulkan hpp vk::enumerateInstanceVersion()会导致segfault
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- std::partition segfault issue
- 为共享 ptr 向量实现复制 c'tor?
- OpenSSL: EC_POINT_set_compressed_coordinates_GFp segfault
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 检查nullptr是否100%保护内存布局不受segfault影响
- OpenCV Tracker 属性访问在 ARM 上因 SEGFAULT 而失败,但在 X86_64 中工作
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?