[英]Deep copy in a move constructor
我是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);
}
該函數的返回是一個右值引用,因此它調用move構造函數。 這是move構造函數的代碼:
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;
}
}
這個move構造函數的問題在於它執行的是淺拷貝而不是深拷貝(就像我猜的每個move構造函數一樣,否則此move構造函數的意義是什么),因此成員數據指向moved_copy.data指向的對象,但是這個對象是操作符* =()函數的局部對象,因此當操作符超出范圍時,該對象消失了,並且我有一個懸空的指針。 所以我的問題是:我應該在move構造函數中執行深層復制嗎?還是可以解決此問題呢?
謝謝。
不,您不應該在move構造函數中進行深層復制。 move構造函數的全部重點是取得某些復制成本很高的資源的所有權。
在這種情況下,可以將data
指針的所有權從現有matrix
轉移到新構造的matrix
對象。 但是想法是將所有權轉移到新對象,而不是與新對象共享所有權。 在這種情況下,這僅意味着將moved_copy.data
設置為nullptr
,這樣在銷毀data
時它不會刪除您的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
防護:無法從自身構造對象,因此move構造函數實際上並不需要(盡管它對move賦值運算符很有用)。
我還從moved_copy
刪除了const
。 移動構造函數需要修改從其移出的對象的狀態,以獲取其資源的所有權,因此不能使用const
。
編輯: 實際上可以從自身構造一個對象,但這並不是您真正需要提防的東西。
此移動構造函數的問題在於,移動之后, data
成員在兩個對象上的值相同,因此當刪除第一個對象時,第二個對象具有指向已刪除內存的指針。
將move構造函數更改為:
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)
,因為對象通常不是通過自身移動來構造的。
不,您不應該在move構造函數中執行深層復制。 否則,您將一無所獲,並且移動構造函數的概念將被破壞:
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;
}
我是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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.