【发布时间】:2021-10-26 19:17:53
【问题描述】:
【问题讨论】:
标签: c++ oop memory-leaks string-literals default-arguments
【问题讨论】:
标签: c++ oop memory-leaks string-literals default-arguments
首先,请注意,您的默认参数值 (c = new char[1]()) 是内存泄漏,因为构造函数稍后不会将 new[]'ed 内存的所有权交给delete[]。使用new[]'ed 内存作为参数的默认值从来都不是很好的理由。
"Rosie" 是一个字符串文字。它的类型为 const char[6],在 C++11 及更高版本中不能按原样分配给非 const char* 指针,需要显式类型转换(其中在这种情况下,您应该使用 const_cast 而不是 C 风格的演员表),例如:
#include <iostream>
#include <string>
class Autoturism
{
static int nr_autoturisme; // nr_autoturis 'active'
char* culoare;
unsigned int a_fabricatie;
public:
Autoturism(char* = nullptr, unsigned int = 0);
~Autoturism();
// TODO: you will also need a copy constructor and a
// copy assignment operator, per the Rule of 3/5/0:
// https://en.cppreference.com/w/cpp/language/rule_of_three
...
};
int Autoturism::nr_autoturisme{ 0 };
Autoturism::Autoturism(char* c, unsigned int an)
{
if (!c) c = const_cast<char*>("");
size_t len = strlen(c);
culoare = new char[len + 1];
strcpy_s(culoare, len + 1, c);
an_fabricatie = an;
++nr_autoturism;
std::cout << "\nConstructorul a fost apelat !";
}
Autoturism::~Autoturism()
{
delete[] culoare;
std::cout << "\nDeconstructorul a fost apelat !";
}
...
int main()
{
Autoturism a1;
Autoturism a2(const_cast<char*>("Rosie"), 1999);
...
return 0;
}
否则,如果您真的打算继续使用 C 风格的字符串处理,那么您应该将c 参数改为const char*(无论如何它应该是pointer-to-const,因为构造函数不会修改指向的数据),例如:
#include <iostream>
#include <string>
class Autoturism
{
static int nr_autoturisme; // nr_autoturis 'active'
char* culoare;
unsigned int a_fabricatie;
public:
Autoturism(const char* = "", unsigned int = 0);
~Autoturism();
// TODO: you will also need a copy constructor and a
// copy assignment operator, per the Rule of 3/5/0:
// https://en.cppreference.com/w/cpp/language/rule_of_three
...
};
int Autoturism::nr_autoturisme{ 0 };
Autoturism::Autoturism(const char* c, unsigned int an)
{
if (!c) c = "";
size_t len = strlen(c);
culoare = new char[len + 1];
strcpy_s(culoare, len + 1, c);
an_fabricatie = an;
++nr_autoturism;
std::cout << "\nConstructorul a fost apelat !";
}
Autoturism::~Autoturism()
{
delete[] culoare;
std::cout << "\nDeconstructorul a fost apelat !";
}
...
int main()
{
Autoturism a1;
Autoturism a2("Rosie", 1999);
...
return 0;
}
但是,话虽如此,你为什么要在 C++ 中使用这种旧的 C 风格的字符串处理呢?您应该改用std::string(您已经包含<string> 标头),让它为您处理所有内存管理,例如:
#include <iostream>
#include <string>
class Autoturism
{
static int nr_autoturisme; // nr_autoturis 'active'
std::string culoare;
unsigned int a_fabricatie;
public:
Autoturism(const std::string & = "", unsigned int = 0);
// std:string is already compliant with the Rule of 3/5/0,
// so the compiler's auto-generated destructor, copy constructor,
// and copy assignment operator will suffice...
};
int Autoturism::nr_autoturisme{ 0 };
Autoturism::Autoturism(const std::string &c, unsigned int an)
{
culoare = c;
an_fabricatie = an;
++nr_autoturism;
std::cout << "\nConstructorul a fost apelat !";
}
int main()
{
Autoturism a1;
Autoturism a2("Rosie", 1999);
...
return 0;
}
【讨论】:
C++ 中的字符串字面量具有用作表达式的常量字符数组类型,极少数例外被转换为指向它们的第一个字符const char * 类型的指针。但是构造函数的第一个参数的类型是 char * 而不是 const char *。所以编译器会报错。
由于默认参数动态分配内存但未删除,构造函数也可能产生内存泄漏。
您至少可以通过以下方式声明构造函数
Autoturism( const char * = "", unsigned int = 0 );
由于内存是动态分配的,您需要明确定义将删除分配的内存的析构函数以及复制构造函数和复制赋值运算符,或者将最后两个定义为已删除。
【讨论】: