在程序中获取调试断言错误
Getting debug assertion errors in program
我只是想创建一个简单的程序来练习一些C++,但我不确定为什么我会收到这个当前错误。输出提供了我想要的结果,但在成功输出后,我不断收到调试断言错误。是内存泄漏还是什么?我不知道会是什么。
页眉:
#include <iostream>
class Record {
char* rec;
public:
Record();
Record(const char*);
Record(const Record&);
~Record();
void display(std::ostream&);
Record& operator=(const char*);
};
std::ostream& operator<<(std::ostream& os, Record& r);
.cpp:
#define _CRT_SECURE_NO_WARNINGS
#include "Record.h"
Record::Record() {
rec = nullptr;
}
Record::Record(const char* s) {
if(s != nullptr) {
rec = new char[strlen(s) + 1];
strcpy(rec, s);
} else {
*this = Record();
}
}
Record::Record(const Record& r) {
*this = r;
}
Record::~Record() {
delete [] rec;
}
void Record::display(std::ostream& os) {
os << rec;
}
Record& Record::operator=(const char* s) {
if (rec != s)
delete [] rec;
if(s != nullptr) {
rec = new char[strlen(s) + 1];
strcpy(rec, s);
}
else {
rec = nullptr;
}
return *this;
}
std::ostream& operator<<(std::ostream& os, Record& r) {
r.display(os);
return os;
}
主要:
#include <iostream>
#include "Record.h"
using namespace std;
int main() {
Record rec1("inheritance"), rec2 = rec1;
cout << rec1 << endl;
cout << rec2 << endl;
rec1 = "overloading";
cout << rec1 << endl;
rec2 = rec1;
cout << rec2 << endl;
return 0;
}
我会把这个作为一个答案,因为它对你的类的行为很重要,并且得出"一切都在工作"的结论是C++语言不那么容易的原因之一。
你编写的main()程序并没有测试一些非常简单的东西。 看这里:
int main() {
Record rec1("inheritance");
Record rec2 = rec1;
}
如果调试此代码,您将看到为 rec2 = rec1 行调用此函数:
Record::Record(const Record& r) {
*this = r;
}
好的,所以调用了复制构造函数。 但是这行代码有什么作用呢?
*this = r;
它不会调用您编写的采用 const char* 的赋值运算符。 相反,它调用采用 Record&的默认赋值运算符,问题是 - 你没有写一个。 因此,最终发生的是调用编译器生成的赋值运算符,该运算符执行浅层复制。
在 main() 程序中,当 main() 返回时,rec2 和 rec1 都将调用各自的析构函数。 问题是 rec2 将删除指针值,好吧,但随后 rec1 将删除相同的指针值(不好),从而导致堆损坏。 我用Visual Studio 2013运行了你的代码,当main()返回时,立即弹出了一个断言对话框。
因此,您需要编写一个采用此签名的用户定义赋值运算符:
Record& Record::operator=(const Record&)
不要从const char*
调用赋值运算符 *this =
并复制构造函数。这通常是不好的做法。在你的例子中,因为你没有定义一个接受const Record&
赋值运算符,所以调用默认赋值运算符,它只是复制指针并执行浅拷贝,这意味着两个Record
在它们的rec
中都有相同的指针——这在 PaulMcKenzie 的回答中被指出并详细描述。但是,即使您确实定义了该赋值运算符,如果您执行与现有赋值运算符相同的操作,则成员变量rec
将未初始化,并且delete
它会导致未定义的行为。
有关讨论,请参阅在复制构造函数中调用赋值运算符,以及除了从构造函数调用赋值运算符之外可以执行哪些操作。
编辑
使程序工作的一种方法是使构造函数看起来像这样。
void Record::InitFrom(const char* s)
{
if(s != nullptr) {
rec = new char[strlen(s) + 1];
strcpy(rec, s);
} else {
rec = nullptr;
}
}
Record::Record(const char* s) {
InitFrom(s);
}
Record::Record(const Record& r) {
InitFrom(r.s);
}
您还可以将新的InitFrom
方法合并到赋值运算符中。
Record& Record::operator=(const char* s) {
if (rec != s) { // this test only really necessary if assigning from Record
delete [] rec;
InitFrom(s);
}
return *this;
}
您可能还具有采用const Record&
的赋值运算符。您确实需要析构函数。
如果不看到初始化记录的值,很难确定发生了什么。 根据您对程序行为和代码的描述,我可以想到一种可能的解释,尽管可能还有其他解释。
我的猜测是 std::ostream 像 c 字符串一样递给 char*,它期望以 \0 结尾的字符序列。 如果您的 Record 已使用不以 \0 结尾的字符序列进行初始化,它将继续执行指针递增,一次流出一个字符,直到到达无效的内存部分。 这将导致未定义的行为,这可能会在标准(即您使用的编译器)的实现中触发调试断言。
当你说这是一个学习练习时,我给你这个猜测,所以我不质疑你的课堂设计,但试图帮助你理解发生了什么。 然而,其他地方的评论是相当相关的。 如果您有记录存储 std::string 而不是字符数组,则不会出现此问题 (以及其他几个可能的问题)。 当然,这个答案可能不会帮助你学习你想要学习的东西。
- OpenCV - Python 断言错误:SAD 算法 - 立体相机视差图计算
- 我收到一个断言错误,但是当我编写 cout 语句时,它会消失
- 尝试删除指向派生对象的基指针时断言错误
- Sysmalloc:使用向量的断言错误
- OpenCV CV 查找单应断言错误计数器 = > 4
- Mat的convertTo函数在OpenCV中将灰度图像的类型转换为CV_32F时抱怨断言错误
- 是什么导致我的C 代码中的断言错误
- 迭代器取消引用断言错误
- boost::shared_ptr 断言错误与 boost::asio:io_service
- CDao数据库断言错误
- STL 迭代器:断言错误
- 断言错误,字符串下标超出范围
- 调试断言错误-OpenCV
- 向量push_back会导致断言错误,但列表push_back有效
- 如何在子进程中禁用断言错误对话框
- OpenCV.norm中的断言错误
- 将功能区添加到现有的非功能区 mfc 项目 - 在 VS2010 中断言错误
- 访问指向像素openCV的指针时发生断言错误
- 断言错误,即使在使用 new 初始化字符指针后也是如此
- 使用结构向量 c++ 的断言错误