C++循环创建对象疑问:对象是否相同及析构必要性
先把你的代码整理出来方便后续分析:
// Queue类相关方法 void Queue::testMethod(){ this->theQueue.clear(); for (int i = 0; i < 3 ; i ++ ){ char *uu = new char[3]; uu[0] = 'd'; uu[1] = static_cast<char>(i); uu[2] = 'r'; MyClass tt(uu, 7); this->theQueue.push_back(tt); } } string Queue::PrintData(){ string data; for ( int i = 0 ; i < this->theQueue.size(); i ++){ data += this->theQueue.at(i).PrintData(); } return data; } // MyClass类相关方法 string MyClass::PrintData(){ string data; data += string(this->AM); data += " "; data += this->Number; // 此处存在类型转换错误 return data; } MyClass::MyClass(char *am, int number) //Constructor { int i = strlen(am); AM = new char[i+1]; strcpy(AM,am); Number = number; } // 主函数 int main() { MyClass myClass1((char *)"1111", 3); MyClass myClass2((char *)"1111", 3); MyClass myClass3((char *)"2222", 3); vector<MyClass> tmpVector; tmpVector.push_back(myClass1); tmpVector.push_back(myClass2); tmpVector.push_back(myClass3); Queue tmpQueue(tmpVector); tmpQueue.testMethod(); cout << tmpQueue.PrintData() << endl; }
执行后输出为 d dr dr,现在逐个解答你的问题:
1. testMethod中的tt对象是否相同?
当然不相同。每次循环迭代里的tt都是栈上的局部自动变量,它的生命周期只限于当前循环体。每次循环都会在栈上分配新的内存空间来存储这个对象,所以每个tt都是独立的实例,内存地址完全不同,自然不是同一个对象。
2. 是否需要在每次迭代中执行析构?
不需要手动调用析构函数——tt作为局部变量,当每次循环迭代结束时,它的生命周期会自动终止,C++会自动调用它的析构函数完成清理。不过这里要提醒你:你的MyClass没有自定义析构函数,默认析构不会释放AM指向的堆内存,会导致内存泄漏。你应该给MyClass补充析构函数:
MyClass::~MyClass() { delete[] AM; }
另外,把ttpush到vector时会触发默认拷贝构造(浅拷贝),这会导致多个MyClass对象共享同一个AM指针,后续析构时会出现重复释放内存的未定义行为,所以你还需要实现拷贝构造函数和拷贝赋值运算符(遵循C++的三/五法则),或者改用智能指针管理内存。
3. 为何会得到d dr dr的输出?
这个输出是由几个代码细节问题共同导致的:
(1)i=0时,uu数组包含字符串结束符'\0'
当i=0时,static_cast<char>(0)就是字符串结束符'\0',此时uu数组内容为{'d', '\0', 'r'}。MyClass构造函数里用strlen(am)计算长度,而strlen会读到'\0'就停止,所以strlen(uu)返回1,你给AM分配了2个字符的内存,strcpy只会把'd'和'\0'拷贝进去。后续PrintData用string(this->AM)转换时,遇到'\0'就截断,所以第一个元素的有效字符串是d。
(2)i=1和i=2时,uu数组缺少结束符,且包含不可打印字符
你创建的uu是new char[3],只赋值了三个元素但没有加'\0',strlen(uu)会越界读取内存直到找到'\0',这属于未定义行为,但在你的环境中刚好读取到了结束符,所以AM被分配了足够内存,拷贝了{'d', char(1), 'r', '\0'}(或char(2))。其中char(1)和char(2)是不可打印的控制字符,输出时不会显示,所以看起来有效字符串是dr。
(3)PrintData方法的类型转换错误
你直接把int类型的Number加到string里,会把数字7转换成对应的ASCII控制字符(响铃符,不可打印),所以输出里看不到数字,最终拼接后就成了d dr dr。正确的写法应该用to_string(this->Number)来转换数字。
内容的提问来源于stack exchange,提问作者Konstantinosdms

