避免C++内存泄漏?



我从C++编码开始,我最近遇到了一个问题,我无法真正找到解决方案,因为我不明白我的错误。

我的程序用于将开尔文转换为摄氏度,但它无法连续进行超过 3 个温度。一旦我通过 4,它就会为我提供正确的转换,但内存问题(超出范围?

"xxx"中的错误:双重释放或损坏(输出):0x0000000001c94c40

当我输入超过四个温度时,它会给出一些随机数,这可能是其他地址的值。

这是我的程序。

#include <iostream>
using namespace std;
unsigned int NumberT {0};           //Definition of the global variables
double* Kelvin=new double[NumberT];
double* Celsius=new double[NumberT];
unsigned int i=0;

double* Conversion (double, double, unsigned int)   //Conversion function
{
for(unsigned int i=0;i<NumberT;++i)
{
Celsius[i]=Kelvin[i]-273.15;
}
return Celsius;
}

void printTemperatures (double, double, unsigned int)   //Print function
{
for(unsigned int i=0;i<NumberT;++i)
{
cout<<"The temperature is "<< Kelvin[i] <<" [K], which is "<< Celsius[i] <<" [C]"<<endl;
}
return;
}

int main ()                     //Main
{   
cout<<"How many temperatures do you want to enter?"<<"n";
cin>>NumberT;
cout<<"What are the temperatures?"<<"n";
for (unsigned int i=0;i<NumberT;++i)
{
cin>>Kelvin[i];
}
Conversion (Kelvin[i], Celsius[i], NumberT);
printTemperatures (Kelvin[i], Celsius[i], NumberT);

delete [] Celsius;
delete [] Kelvin;
return 0;
}

所以我真的很高兴知道我的代码出了什么问题,为什么会这样。我听说我们不应该使用全局变量,这也许可以帮助我理解为什么。

顺便说一下,我有兴趣就如何用良好的语法编写正确的代码提供一些建议,而不会遇到范围问题。因为我想学习如何编写一个最"通用"的函数,以便我可以拉取它并在另一个程序中与其他变量一起使用它。

提前感谢您的支持

PS:我正在使用g ++作为编译器和2011 C++标准

现代C++的一个好习惯是永远不要使用手动内存管理 - 如果您在 C++11 或更高版本的代码中看到newdelete,这是代码异味的标志。

请改用std::make_shared/std::make_unique,使用value typesstd::move

参见赫伯·萨特(Herb Sutter)的最新演讲"默认C++中的泄漏自由"。

对于您的特定示例

unsigned int NumberT {0}; //Definition of the global variables double* Kelvin=new double[NumberT];

您在此处创建一个包含 0 个元素的数组,然后执行大量未分配的内存覆盖,然后尝试释放它。这是行不通的。

在从std::cin读取NumberT后,将数组分配移动到 U,它应该会大大改善。

下一个改进是切换到没有全局变量的更函数式的样式(您不需要它们)。

然后切换到使用std::shared_ptrs。

正如另一个所说。数组初始化是问题所在。 一般来说,由于您不知道元素的初始大小,我会立即考虑向量。在这种情况下,您可以删除"多少个元素...."并引入退出字符或解析 X 分隔值。

当然,使用数组并没有错,但您必须(重新)以正确的大小初始化它们。因此,在您获得NumberT之后.尽管如此,对于数组与矢量,请检查此数组与矢量

我已经发布了一个使用向量的实现,但仍然基于您的方法。

(注意:此代码效率不高,因为它执行大量矢量复制,并且不会引入新概念。请自行搜索引用和 std::move 的参数)

#include <iostream>
#include <vector>
#include <algorithm>
std::vector<double> ToCelcius(std::vector<double> kelvinValues)   //Conversion function
{
std::vector<double> celciusValues;
for (auto value : kelvinValues)
{
celciusValues.push_back(value - 273.15);
}
return celciusValues;
}

void PrintTemperatures(std::vector<double> kelvinSource, std::vector<double> celsiusSource)   //Print function
{
for (uint16_t valueIndex = 0; valueIndex < kelvinSource.size(); valueIndex++)
{
std::cout << "The temperature is " << kelvinSource.at(valueIndex) << " [K], which is " << celsiusSource.at(valueIndex)<< " [C]" << std::endl;
}
}

int main()                     //Main
{
uint16_t numberOfValues;
std::cout << "How many temperatures do you want to enter?" << "n";
std::cin >> numberOfValues;
std::cout << "What are the temperatures?" << "n";
std::vector<double> kelvinValues;
double value;
for (uint16_t i = 0; i< numberOfValues; ++i)
{
if (std::cin >> value) {
kelvinValues.push_back(value);
}
continue;
}
auto celciusValues = ToCelcius(kelvinValues);
PrintTemperatures(kelvinValues, celciusValues);
return 0;
}

您的问题是在进行内存分配时NumberT0
当您执行以下操作时:

double* Kelvin=new double[0];

不执行初始化,因此指针具有不确定的值。 写入和读取此记忆具有不确定的行为。

当您在具有不确定值的指针上使用delete[]时,您的代码可能会崩溃。

此问题非常适合使用vector<double>而不是double[]数组,没有理由不使用此容器提供的动态内存处理工具。

用作此示例:

//Replace arrays with vectors
vector<double> Kelvin;
vector<double> Celsius;
//in your main to read user input
for (unsigned int i=0;i<NumberT;++i)
{
double read;
cin >> read;
Kelvin.push_back(read);
}
//In your conversion function
for (std::vector<double>::iterator it = Kelvin.begin(); it != Kelvin.end(); ++it)
{
Celsius.push_back((*it)-273.15);
}

其他提示:

-你不需要声明全局变量(例如,你可以在main()开始时声明它)并通过引用传递变量,如下所示:

void Conversion (vector<double> & Kelvin, vector<double> & Celsius);  

-当vector超出范围(在您的main()结束时)时,他们将为您完成delete工作。

相关内容

  • 没有找到相关文章

最新更新