c++ - 分配给 gslice_array 会产生运行时错误
问题描述
我正在尝试构建一个派生的类std::valarray<T>
以在其上使用我自己的方法。我遇到了关于使用operator[]赋值的问题。经过一番努力,我想我终于发现了问题所在。分配给std::slice_array<T>
不构成问题,分配给std::gslice_array<T>
就可以了。
这是重现问题的代码:
#include <valarray>
#include <cassert>
#include <iostream>
int main() {
const size_t rows = 16;
const size_t cols = 24;
assert(rows%8 == 0);
assert(cols%8 == 0);
// return b_th 8x8 block
auto get_block = [&rows, &cols](size_t b) -> std::gslice {
return std::gslice((b / (cols/8))*8*cols + (b % (cols/8))*8, {8, 8}, {cols, 1});
};
// zeros(rows, cols) but 1D
std::valarray<int> v(0, rows*cols);
auto print = [&rows, &cols, &v]() -> void {
for (size_t i=0; i<rows; i++) {
for (size_t j=0; j<cols; j++)
std::cout << " " << v[i*cols + j];
std::cout << "\n";
}
std::cout << std::endl;
};
print();
// this is OK
v[get_block(1)] = 1;
print();
// this is also OK
std::slice_array<int> s = v[std::slice(2*cols, cols, 1)];
s = 2;
print();
// ???
std::gslice_array<int> g = v[get_block(3)];
// g = 3; // this line causes runtime error
print();
return 0;
}
知道如何解决这个问题吗?
解决方案
如果你使用 g++,你有悬空引用,这会导致未定义的行为和崩溃。
这是 g++ 中的一个错误。
在这一行:
std::gslice_array<int> g = v[get_block(3)];
通过调用get_block(3)
临时实例gslice
来创建。方法valarray::operator[](gslice)
称为取这个临时gslice
的。让我们看看它的实现:
template<typename _Tp>
inline gslice_array<_Tp>
valarray<_Tp>::operator[](const gslice& __gs)
{
return gslice_array<_Tp> (_Array<_Tp>(_M_data), __gs._M_index->_M_index);
}
它需要引用 constgslice
所以临时实例gslice
可以绑定到__gs
,当从这个方法返回时,对象的gslice_array
创建:
template<typename _Tp>
inline
gslice_array<_Tp>::gslice_array(_Array<_Tp> __a,
const valarray<size_t>& __i)
: _M_array(__a), _M_index(__i) {}
其中_M_array
和_M_index
的gslice_array
定义为:
_Array<_Tp> _M_array;
const valarray<size_t>& _M_index; // <------------- here is reference !
To _M_index
ofgslice_array
已分配__gs._M_index->_M_index
。是什么__gs._M_index
?它是一个gslice
名为 as的内部结构_Indexer
。它使用引用计数器机制来延长自身的生命周期。只有当被复制(通过复制构造函数或复制赋值运算符)时,引用计数器_Indexer
才能增加
gslice
,但在此代码中不执行这些操作。因此,当gslice
as 临时对象被删除时,_M_index
of__gs
也被删除,最后出现悬空引用。
错误在哪里?保留索引器成员的引用,删除时gslice
删除。如果索引器持有指向 valarray 的指针而不是引用,它就不会发生。引用的存储不是过渡的。
作为解决方法,创建gslice
如下的 L 值实例:
auto b = get_block(3);
std::gslice_array<int> g = v[b];
g = 3;
print();
然后,一切正常。
推荐阅读
- react-native - 在 React Native 中在图像上绘制点并在不同的屏幕尺寸上渲染
- javascript - MSAL.JS 的异步/等待/承诺问题
- r - 错误:`mutate()` 输入`coding` 有问题。x 没有适用于“字符”类对象的“选择”方法
- web - 在 Hugo 主题上创建嵌套菜单?
- python - 如何在面板数据上使用 LSTM?
- remote-desktop - 无法连接到远程桌面或远程管理员
- autohotkey - AutoHotKey - 函数不能包含函数错误
- swiftui - 导航链接导致 Swift UI 中出现灰屏
- excel - #officewriter - 如何运行宏
- javascript - HTML 更改时从零重新创建 IndexedDB 数据库