我是C ++ 11的新手,所以我仍然坚持其概念。
这是我的问题:
我有一个矩阵类:
class matrix
{
private:
double** data;
size_t number_lines;
size_t number_columns;
size_t capacity_lines;
size_t capacity_columns;
public:
....
}
我已经提供了一个复制构造函数,一个移动构造函数......
我已经将乘法运算符*(double x)重载为乘以标量x的矩阵元素并返回乘法矩阵。 这是代码:
matrix matrix::operator*(double lambda)
{
double** aux_data = new double*[number_lines];
for (size_t i = 0; i < number_lines; i++)
{
aux_data[i] = new double[number_columns];
for (size_t j = 0; j < number_columns; j++)
aux_data[i][j] = lambda*data[i][j];
}
return matrix(aux_data, number_lines, number_columns);
}
函数的返回是一个右值引用,因此它调用了移动构造函数。这是移动构造函数的代码:
matrix::matrix(const matrix&& moved_copy)
{
if (this != &moved_copy)
{
number_columns = moved_copy.number_columns;
number_lines = moved_copy.number_lines;
data = moved_copy.data;
}
}
这个移动构造函数的问题在于它执行浅拷贝而不是深拷贝(就像我猜的每个移动构造函数,否则这个移动构造函数是什么)所以成员数据< / em>指向 moved_copy.data 指向的对象,但此对象是operator * =()函数的本地对象,因此当操作符超出范围时,对象消失了,我有一个悬空指针。所以我的问题是:我应该在移动构造函数中执行深层复制,还是有办法解决这个问题而不这样做?
谢谢。
答案 0 :(得分:4)
不,你不应该在移动构造函数中制作深层副本。移动构造函数的重点是获取一些复制成本高昂的资源。
在这种情况下,您的data
指针的所有权可以从现有的matrix
转移到新构造的matrix
对象。但我们的想法是将所有权转移到新对象,而不是与新对象共享所有权。在这种情况下,这只意味着将moved_copy.data
设置为nullptr
,这样就不会在data
被删除时删除它。
matrix::matrix(matrix&& moved_copy)
{
number_columns = moved_copy.number_columns;
number_lines = moved_copy.number_lines;
data = moved_copy.data;
moved_copy.data = nullptr;
}
请注意,我还删除了你的if
守卫:没有办法从自身构造一个对象,因此移动构造函数并不需要它(虽然它对移动赋值运算符很有用)。
我还从const
删除了moved_copy
。移动构造函数需要修改移动对象的状态以获取其资源的所有权,因此不能使用const
。
编辑:从actually possible构建一个对象,但它并不是你真正需要防范的东西。
答案 1 :(得分:0)
此移动构造函数的问题在于data
成员在移动后在两个对象上具有相同的值,这样当第一个对象被删除时,第二个对象具有指向已删除内存的指针。
将移动构造函数更改为:
matrix::matrix(matrix&& moved_copy)
{
if (this != &moved_copy)
{
number_columns = moved_copy.number_columns;
number_lines = moved_copy.number_lines;
data = moved_copy.data;
moved_copy.number_columns = 0;
moved_copy.number_lines = 0;
moved_copy.data = nullptr;
}
}
可以省略检查if (this != &moved_copy)
,因为对象通常不是通过自身移动来构造的。
答案 2 :(得分:0)
不,您不应该在移动构造函数中执行深层复制。否则你不会获得任何东西,移动构造函数的概念就会被破坏:
matrix::matrix(matrix&& moved_copy)
: data(moved_copy.data),
number_rows(moved_copy.number_rows),
number_columns(moved_copy.number_columns),
capacity_rows(moved_copy.capacity_rows),
capacity_columns(moved_copy.capacity_columns) {
moved_copy.data = nullptr;
}
此外,避免将二元运算符定义为成员函数,因为您打破了交换性的数学属性。也就是说,虽然:
matrix M;
...
matrix K = m * 2.0;
会奏效。以下赢了:
matrix M;
...
matrix K = 2.0 * m;
首选将二元运算符定义为自由函数。
matrix operator*(matrix const &m, double lambda) {
matrix out(m.aux_data, m.number_rows, m.number_columns);
...
return out;
}
matrix operator*(double lambda, matrix const &m) {
return m * lambda;
}
答案 3 :(得分:0)
我是C ++ 11的新手。
所以你不会介意我建议你用std :: vector来实现你的矩阵,因为你的所有移动问题都会解决:
这是一个实施的开始:
#include <vector>
#include <cstddef>
#include <iostream>
class matrix
{
private:
std::vector<double> storage_;
std::size_t row_capacity_;
std::size_t rows_;
std::size_t cols_;
std::size_t get_location(std::size_t row, std::size_t col) const
{
return row * row_capacity_ + col;
}
public:
matrix(std::size_t rows, std::size_t cols, std::size_t row_capacity, std::size_t col_capacity)
: storage_(row_capacity * col_capacity)
, row_capacity_(row_capacity)
, rows_(rows)
, cols_(cols) {}
matrix(std::size_t rows, std::size_t cols)
: matrix(rows, cols, rows, cols) {}
//
// note that all move/copy operations are automatically generated.
// "The rule of none"
//
std::size_t get_rows() const { return rows_; }
std::size_t get_cols() const { return cols_; }
std::size_t get_capacity_rows() const { return row_capacity_; }
std::size_t get_capacity_cols() const { return storage_.capacity() / row_capacity_; }
double& at(std::size_t row, std::size_t col)
{
return storage_[get_location(row, col)];
}
double const& at(std::size_t row, std::size_t col) const
{
return storage_[get_location(row, col)];
}
};
int main()
{
auto m = matrix(3, 3);
m.at(1, 1) = 2;
std::cout << m.at(1, 1) << std::endl;
std::cout << m.get_cols() << std::endl;
std::cout << m.get_rows() << std::endl;
std::cout << m.get_capacity_cols() << std::endl;
std::cout << m.get_capacity_rows() << std::endl;
}