使用“new Mystring”会造成内存泄漏吗? C++

问题描述 投票:0回答:1

在有人开始说我应该使用

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

c++ memory memory-leaks return new-operator
1个回答
0
投票

您在

new
中使用
operator+
确实会造成内存泄漏。每个
new
都需要一个匹配的
delete

您正在正确地删除

new
。问题是,当您创建
temp
对象作为
*this
的副本时,
temp.str
的分配大小仅足以容纳
this->str
值的副本,但随后您将
rhs.str
连接到
temp.str 
,它不够大,无法容纳
rhs.str
的副本,因此您最终会写入周围的内存。这就是为什么你会发生堆损坏。

© www.soinside.com 2019 - 2024. All rights reserved.