使用括号运算符实现矩阵类的安全方法
Safe way to implement matrix class with bracket operators
我只是为了它而写一个二维矩阵类,包装一个向量向量。
由于矩阵必须具有正维数,我确保矩阵不会构造错误,从那时起,我假设矩阵至少有一个元素:
Matrix2D::Matrix2D(size_t rows, size_t cols)
{
if (rows == 0 || cols == 0)
{
throw std::invalid_argument("Matrix cannot have zero as dimension");
}
...
我想为用户提供一种通过使用级联[]
访问和修改特定元素的方法(即m[1][1]
)。但是,我不希望用户能够修改矩阵的维度或修改一行中的列数。我目前提供如下所示的重载operator[]
的方法是不够的,因为用户可以使用非 const 版本(修改特定元素所必需的)来修改列数:
std::vector<double>& operator[](size_t r);
const std::vector<double>& operator[](size_t r) const;
通过做m[0] = std::vector<double>(0)
.
有没有办法在保持双括号语法的同时防止这种垮台?
我知道我可以使用像m(1, 1)
这样的operator()
,但我对尝试使用双括号语法感到好奇。
您的operator[]
可以返回定义了operator[]
的代理对象。像这样:
class Matrix2D
{
std::vector<std::vector<double>> rows;
class Proxy
{
friend class Matrix2D;
std::vector<double> &v;
Proxy(std::vector<double> &v) : v(v) {}
public:
double& operator[] (size_t c) const { return p[c]; }
};
public:
Proxy operator[] (size_t r)
{
return { rows[r]; }
}
};
但是请注意,使用向量向量来表示 2D 矩阵通常是一个坏主意,因为它对缓存非常不友好。如果您只存储一个大小rows * cols
的std::vector<double>
并手动索引到其中,它将更接近实际可用性。
这个想法是让Matrix::operator[](size_t)
返回一个代理对象,其operator[](size_t)
返回对矩阵元素的(const)引用。
//untested
template<class T>
class Matrix
{
public:
using value_type = T;
private:
std::vector<value_type> _data;
class Row
{
Matrix& _m;
size_t _row;
public:
Row(Matrix& m, size_t row) : _m(m), _row(row) {}
value_type& operator[](size_t col) { return _m.at(_row, col); }
}
public:
// constructor(s) here
value_type& at(size_t row, size_t col) { return /*...*/; }
Row operator[](size_t row) { return Row{*this, row}; }
}
待添加:常量版本、构造函数、索引、维度处理。完成后,您将能够像这样使用它:
Matrix<double> m{/*...*/};
m[1][2] = 28;
auto row = m[1];
row[1] = 18;
//row = std::vector<double>(0); // ERROR
Peter Gottschling在他的优秀著作《发现现代C++》(Addison Wesley 2016)中展示了Matrix[][]
的模板解决方案。 他的方法使用上述代理类和奇怪的重复模板模式(CRTP)。
相关文章:
- 将传入的网络"char*"数据转换为"uint8_t"并返回的安全方法是什么?
- 在 c++ 中从执行的 shell 命令获取返回状态的安全方法是什么?
- 在C++线程内实现多个计时器的最安全方法
- 最有效的安全方法将 std::map<int, std::shared_ptr> 转换为 std::<Base>map<int, std::shared_ptr<D
- 重新分配指针阵列的一部分的安全方法
- 将整数添加到数组值而无需调用它的最安全方法
- 使用括号运算符实现矩阵类的安全方法
- 将空隙动态铸造到类型的安全方法?
- C/通过套接字发送time_t的最安全方法
- 交换两个类实例的最安全方法
- 将uint16_t投射到wchar_t的安全方法
- 从字符串中读取溢出双倍作为'inf'的安全方法
- 期货是检查单个线程完成情况的安全方法吗
- 在C++中动态分配向量的安全方法是什么
- 在C++类中构建互斥保护的线程安全方法
- C++和跳出动态生成代码的安全方法
- 这是实现错误处理的安全方法吗
- 将长整数转换为字符数组的最安全方法是什么
- 缓存 PID 到端口映射窗口的安全方法
- 将无符号长整整除以无符号长整型的最安全方法