gpt4 book ai didi

c++ - 覆盖矩阵中 vector 对象的代理类中的赋值运算符?

转载 作者:行者123 更新时间:2023-11-30 04:55:03 24 4
gpt4 key购买 nike

我有一个小问题。我有一个 Matrix 类定义如下(以行优先形式):

template<typename T>
class Matrix {
private:
class RowVector {
private:
T *_vec;
std::size_t _l;

public:
RowVector(T *vec, std::size_t l);

const T &operator[](std::size_t index) const;
T &operator[](std::size_t index);

operator std::vector<T>() const;
};

std::vector<T> _data;
std::size_t _m;
std::size_t _n;

public:
Matrix(std::size_t m, size_t n, const T &elem = T());

const RowVector operator[](std::size_t index) const;
RowVector operator[](std::size_t index);

std::size_t getm() const;
std::size_t getn() const;
void fill(const T &elem);
void fillRow(std::size_t index, const T &elem);
void fillCol(std::size_t index, const T &elem);

Matrix &transpose(unsigned int i = 1);

const std::vector<T> &data() const;
};

并希望重载两个 RowVector 运算符=

typename Matrix<T>::RowVector &operator=(const std::vector<T> &vec);
typename Matrix<T>::RowVector &operator=(const Matrix<T> &mat);

因此我可以使用 A[0] 返回 RowVector & 并使用 vector 或矩阵重新分配其值。请记住,我(大概)可以忽略三规则,因为我没有为客户端提供构造 RowVector 对象的明确方法。

但是,在尝试为重载编写函数体时,我遇到了一个问题:那个

(1) 我无法复制构造一个将在 operator= 的范围之外持续存在的 vector/矩阵对象,以便我可以将其 data() 分配给 _vec 及其 size()_l

(2) 我不能直接修改_data,因为它不是静态变量;即使可以,我也无法发现索引,因此我无法覆盖封闭的 Matrix 对象中的相关内存区域。

你知道有什么方法可以做到这一点吗?这对我的类(class)来说是两个非常有用的 Assets 。

我希望能够写出这样的东西:

Matrix<int> A(3, 4);
std::vector<int> v {1, 2, 3, 4};
Matrix<int> row(1, 4, 3);
// *****************
A[0] = v;
A[1] = row;
// *****************

(希望我的变量名是不言自明的)我认为我的原型(prototype)是正确的,但我就是找不到方法来做到这一点。

谢谢!

最佳答案

T *_vec;
std::size_t _l;

这是一个有问题的设计!我并不是说它本身不正确,但是您需要自己正确管理内存。在这方面,忽视三(五)的规则是非常危险的。您有一个指向(可能?)动态分配内存的指针,因此必须有一些实例负责删除它(不一定是您的RowVector,但还有什么然后呢?)。

从纯粹的技术角度来看,您甚至可以让 _vec 指向一些 vector 的数据,提供您保证只要您想要访问数据,这个其他 vector 就会存在通过指针——尽管这通常需要相当多的努力。

最安全的做法是让每一行维护自己的数据,从另一个 vector 复制(或移动)数据。然后最简单的方法是将数据存储在它自己的 std::vector 中(替换原始指针)。

如果您想避免复制数据,而是在不同矩阵及其行之间共享数据,那么您可以通过 std::shared_ptr 维护数据 - 或者维护原始数组或什至可能是堆分配的 std::vector

如果您选择 std::vectorstd::shared_ptr,那么复制和移动构造函数和赋值运算符将变得非常简单:

class C
{
public:
C(C const&) = default;
C(C&&) = default;
C& operator= (C const&) = default;
C& operator= (C&&) = default;
};

所有这些默认值都将根据成员进行复制/移动,并且 std::vectorstd::shared_ptr 都已经有合适的构造函数和运算符可用,所以你会没事的——你现在可以违反五规则,删除析构函数,因为默认的(调用所有成员的析构函数)就足够了。

如果您考虑共享指针:请注意您不能将 std::vector 的数据分配给:std::vector 进行自己的内存管理,并且您最终将被双重删除,因此在这种特定情况下,您仍然必须创建一个拷贝。您可能最终会遇到多个构造函数和赋值运算符:

std::shared_ptr<std::vector<int>> _data;

// assign shared pointers
RowVector(RowVector const&) = default;
RowVector(RowVector&&) = default;

// need to create copies of: we never know about the scope of the vector passed!
RowVector(std::vector<int> const& data) : _data(new std::vector<int>(data)) { }
RowVector(std::vector<int>&& data) : _data(new std::vector<int>(std::move(data))) { }

// we *are* sharing already -> no need to copy:
RowVector(std::shared_ptr<std::vector<int>& data) : _data(data) { }

赋值运算符类似。

旁注:如果你想要一个数学 nxm 矩阵,很确定你不想要一个锯齿状的数组。我假设您的 Matrix 类的构造函数已经创建了一个适当的 vector vector ,然后对于赋值,您还没有检查长度:

// defaults not suitable any more!
RowVector& RowVector::operator=(RowVector const& other)
{
// still assuming shared pointer:
// (for vector, replace -> with .)
if(other._data->size() != _data.size())
{
throw SomeException();
}
_data = other._data;
}
RowVector(RowVector&& other)
{
if(other._data->size() != _data.size())
{
throw SomeException();
}
_data = std::move(other._data);
}

关于c++ - 覆盖矩阵中 vector 对象的代理类中的赋值运算符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53292701/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com