使用向量构造函数分配动态内存
Using a vector constructor to assign dynamic memory
很可能我正在尝试做的是糟糕的练习。如果是这样,请告诉我,这样我就可以停下来。无论如何,我正在研究一些使用动态内存存储矩阵数据数组的基本矩阵数学函数。我试图弄清楚如何将传递给构造函数的向量转换为该数组,但我得到了一些奇怪的结果。这是简单的版本。
Header:
class Matrix {
public:
unsigned int size = 4;
float *M;
Matrix(std::vector<float> values) : M(&values[0]){}
~Matrix() = default;
};
和测试文件:
int main(){
Matrix m(std::vector<float>{ 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 2.0f, 3.0f, 4.0f,
5.0f, 6.0f, 7.0f, 8.0f,
9.0f, 10.0f, 11.0f, 12.0f });
return 0;
}
结果是……错误的。一切似乎都有效(从调试时观察值)直到 return 来自构造函数。我的猜测是 Visual Studio 的调试器在骗我,而且它发生的时间比那早。
所以除了大小没有改变之外,还有什么事发生?有一个更好的方法吗?另外,是否可以接受 std::initializer_list 并将该数据提供给动态指针?
您传递的向量是一个临时对象。一旦构造函数完成,临时向量将不复存在,因此您存储的地址 (&values[0]
) 将因此指向垃圾。您的代码实际上可能有效,但实际上它也可能使您的计算机崩溃,或者给您泡咖啡,或者做任何其他未定义的事情。
如果你想保持相同的界面(即传入一个向量),你需要将数据复制出来。这样的事情会让你开始
Matrix(std::vector<float> values) : M(new float[values.size()])
{
std::copy(values.begin(), values.end(), M);
}
但现在您必须在析构函数中释放 M,并实现适当的复制构造函数和赋值运算符。也不要忘记你的移动构造函数和赋值运算符;)查看 std::unique_ptr
和 std::shared_ptr
(当然还有 std::vector
)以获得更好的内存管理方法。
使用您当前的代码,您正在存储一个悬空指针。向量及其数据将在调用 Matrix
.
的构造函数后被销毁
您可以使用以下选项之一解决问题。
选项 1
不要使用原始指针。请改用 std::vector<float>
。替换
float *M;
来自
std::vector<float> M;
然后,您可以将构造函数更新为:
Matrix(std::vector<float> values) : M(values){}
选项 2
为M
分配内存,然后从构造函数的输入参数中复制数据。
Matrix(std::vector<float> values) : M(new float[values.size()])
{
std::copy(values.begin(), values.end(), M);
}
如果使用此选项,则需要实现适当的复制构造函数、复制赋值运算符和析构函数。记得继续阅读 The Rule of Three。
很可能我正在尝试做的是糟糕的练习。如果是这样,请告诉我,这样我就可以停下来。无论如何,我正在研究一些使用动态内存存储矩阵数据数组的基本矩阵数学函数。我试图弄清楚如何将传递给构造函数的向量转换为该数组,但我得到了一些奇怪的结果。这是简单的版本。
Header:
class Matrix {
public:
unsigned int size = 4;
float *M;
Matrix(std::vector<float> values) : M(&values[0]){}
~Matrix() = default;
};
和测试文件:
int main(){
Matrix m(std::vector<float>{ 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 2.0f, 3.0f, 4.0f,
5.0f, 6.0f, 7.0f, 8.0f,
9.0f, 10.0f, 11.0f, 12.0f });
return 0;
}
结果是……错误的。一切似乎都有效(从调试时观察值)直到 return 来自构造函数。我的猜测是 Visual Studio 的调试器在骗我,而且它发生的时间比那早。
所以除了大小没有改变之外,还有什么事发生?有一个更好的方法吗?另外,是否可以接受 std::initializer_list 并将该数据提供给动态指针?
您传递的向量是一个临时对象。一旦构造函数完成,临时向量将不复存在,因此您存储的地址 (&values[0]
) 将因此指向垃圾。您的代码实际上可能有效,但实际上它也可能使您的计算机崩溃,或者给您泡咖啡,或者做任何其他未定义的事情。
如果你想保持相同的界面(即传入一个向量),你需要将数据复制出来。这样的事情会让你开始
Matrix(std::vector<float> values) : M(new float[values.size()])
{
std::copy(values.begin(), values.end(), M);
}
但现在您必须在析构函数中释放 M,并实现适当的复制构造函数和赋值运算符。也不要忘记你的移动构造函数和赋值运算符;)查看 std::unique_ptr
和 std::shared_ptr
(当然还有 std::vector
)以获得更好的内存管理方法。
使用您当前的代码,您正在存储一个悬空指针。向量及其数据将在调用 Matrix
.
您可以使用以下选项之一解决问题。
选项 1
不要使用原始指针。请改用 std::vector<float>
。替换
float *M;
来自
std::vector<float> M;
然后,您可以将构造函数更新为:
Matrix(std::vector<float> values) : M(values){}
选项 2
为M
分配内存,然后从构造函数的输入参数中复制数据。
Matrix(std::vector<float> values) : M(new float[values.size()])
{
std::copy(values.begin(), values.end(), M);
}
如果使用此选项,则需要实现适当的复制构造函数、复制赋值运算符和析构函数。记得继续阅读 The Rule of Three。