在有人开始说我应该使用
std::string
之前,这是课程的练习部分,我试图在这里学习,而不仅仅是为了让某些东西发挥作用。
代码运行正常,但我试图了解何时发生内存泄漏,何时不发生。以及如何检查!!
Mystring Mystring::operator+(const Mystring rhs) {
Mystring *temp = new Mystring { *this };
int a = strcat_s(temp->str, strlen(str) + strlen(rhs.str)+1, rhs.str);
return (*temp);
}
我知道我正在使用一个由
*temp
创建的 new Mystring
指针,并且我知道我没有使用 delete
来实现 new
(而且我不知道该把它放在哪里,通过方式...)
但是,代码运行正常,没有错误,有没有办法检查内存泄漏?这是漏水吗?为什么?或者如果没有,为什么不呢?
这是所有内容的代码,有问题的部分在最后:
#include <iostream>
#include "Mystring.h"
using namespace std;
int main() {
Mystring s1 {"FRANK"};
s1 = s1 + "*****";
cout << s1 << endl; // FRANK*****
return 0;
}
#ifndef _MYSTRING_H_
#define _MYSTRING_H_
class Mystring
{
friend std::ostream& operator<<(std::ostream& os, const Mystring& rhs);
friend std::istream& operator>>(std::istream& in, Mystring& rhs);
private:
char* str; // pointer to a char[] that holds a C-style string
public:
Mystring(); // No-args constructor
Mystring(const char* s); // Overloaded constructor
Mystring(const Mystring& source); // Copy constructor
Mystring(Mystring&& source); // Move constructor
~Mystring(); // Destructor
Mystring& operator=(const Mystring& rhs); // Copy assignment
Mystring& operator=(Mystring&& rhs); // Move assignment
Mystring operator+(const Mystring rhs);
void display() const;
int get_length() const; // getters
const char* get_str() const;
};
#endif // _MYSTRING_H_
#include <iostream>
#include <cstring>
#include "Mystring.h"
// No-args constructor
Mystring::Mystring()
: str{nullptr} {
str = new char[1];
*str = '\0';
}
// Overloaded constructor
Mystring::Mystring(const char *s)
: str {nullptr} {
if (s==nullptr) {
str = new char[1];
*str = '\0';
} else {
str = new char[strlen(s)+1];
//strcpy(str, s);
strcpy_s(str, strlen(s)+1, s);
}
std::cout << "Overloaded constructor used" << std::endl;
}
// Copy constructor
Mystring::Mystring(const Mystring &source)
: str{nullptr} {
str = new char[strlen(source.str)+ 1];
//strcpy(str, source.str);
strcpy_s(str, strlen(source.str) + 1, source.str);
std::cout << "Copy constructor used" << std::endl;
}
// Move constructor
Mystring::Mystring( Mystring &&source)
:str(source.str) {
source.str = nullptr;
std::cout << "Move constructor used" << std::endl;
}
// Destructor
Mystring::~Mystring() {
delete [] str;
}
// Copy assignment
Mystring &Mystring::operator=(const Mystring &rhs) {
std::cout << "Using copy assignment" << std::endl;
if (this == &rhs)
return *this;
delete [] str;
str = new char[strlen(rhs.str) + 1];
//strcpy(str, rhs.str);
strcpy_s(str, strlen(rhs.str) + 1, rhs.str);
return *this;
}
// Move assignment
Mystring &Mystring::operator=( Mystring &&rhs) {
std::cout << "Using move assignment" << std::endl;
if (this == &rhs)
return *this;
delete [] str;
str = rhs.str;
rhs.str = nullptr;
return *this;
}
// Display method
void Mystring::display() const {
std::cout << str << " : " << get_length() << std::endl;
}
// getters
int Mystring::get_length() const { return strlen(str); }
const char *Mystring::get_str() const { return str; }
// overloaded insertion operator
std::ostream &operator<<(std::ostream &os, const Mystring &rhs) {
os << rhs.str;
return os;
}
// overloaded extraction operator
std::istream &operator>>(std::istream &in, Mystring &rhs) {
char *buff = new char[1000];
in >> buff;
rhs = Mystring{buff};
delete [] buff;
return in;
}
Mystring Mystring::operator+(const Mystring rhs) {
Mystring temp{ *this };
int a = strcat_s(temp.str, strlen(str) + strlen(rhs.str) + 1, rhs.str);
return (temp);
}
我尝试在不使用
new
的情况下执行此操作:
Mystring Mystring::operator+(const Mystring rhs) {
Mystring temp { *this };
int a = strcat_s(temp.str, strlen(str) + strlen(rhs.str)+1, rhs.str);
return (temp);
}
但是该代码在最后执行析构函数时会抛出错误:
检测到堆损坏
为什么其他代码不起作用?我期望
return
函数通过复制返回 Mystring temp
,然后通过超出范围来删除该临时值,但不知何故发生了移动而不是复制,并且来自 str
的 temp
指针结束结果对象 (s1
) 中,这会在调用 s1
的析构函数时导致错误。
有没有办法做到这一点而不需要
new
?
您在
new
中使用 operator+
确实会造成内存泄漏。每个 new
都需要一个匹配的 delete
。
您正在正确地删除
new
。问题是,当您创建 temp
对象作为 *this
的副本时,temp.str
的分配大小仅足以容纳 this->str
值的副本,但随后您将 rhs.str
连接到 temp.str
,它不够大,无法容纳 rhs.str
的副本,因此您最终会写入周围的内存。这就是为什么你会发生堆损坏。