为什么内存泄漏仅在赋值运算符重载但不在复制构造函数中以及复制和交换习惯用法如何解析时发生

tan*_*anz 4 c++ memory-leaks

PS:我是编程新手,所以请用简单的语言回答我的疑惑.我找到了几个答案,但无法理解它们.下面是复制构造函数和赋值运算符重载.

template <class T>
Mystack<T>::Mystack(const Mystack<T> &source)            // copy constructor
{
    input = new T[source.capacity];
    top = source.top;
    capacity = source.capacity;
    for (int i = 0; i <= source.top; i++)
    {
        input[i] = source.input[i];
    }
}


template <class T>
Mystack<T> & Mystack<T>::operator=(const Mystack<T> &source)       // assignment operator overload 
{
    input = new T[source.capacity];
    top = source.top;
    capacity = source.capacity;

    for (int i = 0; i <= source.top; i++)
    {
        input[i] = source.input[i];
    }
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

主要功能片段

   Mystack <int> intstack = tempstack; (copy constructor)
    Mystack <int> floatstack, temp_1;
    floatstack = temp_1;  (assignment operator)
Run Code Online (Sandbox Code Playgroud)

理解:我理解我们需要复制和赋值运算符,以便我们可以进行深度复制,以防我们使用堆内存,因此当我们删除其中一个对象时不会有悬空指针问题.

有人可以回答下面的问题.

1 .:我的理解是否正确?

2 . :开发人员建议我在赋值运算符中有内存泄漏.如果是,可以请一些人解释我怎么样?

3.复制构造函数与赋值运算符具有或多或少相同的代码,那么为什么我只有在赋值运算符的情况下才有内存泄漏但在复制构造函数中却没有.

4 . :如果我真的有内存泄漏.什么魔术副本和交换习惯用于解决内存泄漏问题.

PS:它不是完整的运行代码.在实际代码中,对象确实包含一些数据.请耐心!

Who*_*aig 7

"我的理解是否正确?"

是的你似乎明白了.完整的理由最好由三规则概念描述.如果你发现自己必须实现三个中的任何一个(copy-ctor,赋值操作或析构函数)来管理动态内存,你可能需要全部三个(也许更多,请参阅文章).


"开发人员已经建议我在赋值运算符中有内存泄漏.如果是,有些人可以解释一下我是怎么回事?"

你没有发布你的默认构造函数,但我认为它看起来像这样:

Mystack<T>::Mystack(size_t size = N)
{
    input = new T[size];
    top = 0;
    capacity = size;
}
Run Code Online (Sandbox Code Playgroud)

或类似的东西.现在,让我们看看你的赋值运算符会发生什么:

input = new T[source.capacity]; 
Run Code Online (Sandbox Code Playgroud)

嗯,这个物体的价值恰好发生了什么input?它不再可达,随之而来的是其中的记忆不再可回收.它被泄露了.


"复制构造函数与赋值运算符具有或多或少相同的代码,那么只有在赋值运算符的情况下才会出现内存泄漏,但在复制构造函数中却没有."

在复制文件的复制结构的目标中没有分配先前的值.即不指向任何东西(怎么可能?你只是 - 现在正在创建目标对象).因此,没有泄漏.inputinput


"如果我真的有内存泄漏.那个内存泄漏得到解决的魔术副本和交换习惯用法."

copy-swap惯用法使用copy-constructor创建一个临时保存的值副本,然后使用赋值运算符将对象"guts"与该副本交换.在执行此操作时,当析构函数触发时,外出临时将破坏目标对象的原始内容,而目标对象将临时传入内容的所有权作为其自身.

这提供了多种好处(是的,一个缺点),并且在这里有出色的描述.代码中的一个简单示例是:

template <class T>
void Mystack<T>::swap(Mystack<T>& src)
{
    std::swap(input, src.input);
    std::swap(top, src.top);
    std::swap(capacity, src.capacity);
}
Run Code Online (Sandbox Code Playgroud)

并且您的赋值运算符变为:

template <class T>
Mystack<T> & Mystack<T>::operator=(Mystack<T> src) // NOTE by-value intentional,
                                                   // invokes copy-ctor.
{
    this->swap(src);
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

现在你有一个复制(在copy-ctor中)进行管理的实现.此外,如果发生任何异常,他们将在构建价值副本期间这样做,而不是在此处.这个物体被污染的可能性不确定状态减少了(一件好事)

如果你对我之前提到的缺点感到好奇,那么考虑一下自我赋值(x = x;)将如何与这样的范式一起发挥作用.老实说,我个人并不认为自我指派无效率是一个缺点.如果您的代码经常光顾x = x;您的设计,那么您的设计中可能会有一股腐臭味.


强烈建议您阅读有关该概念的其他信息的文章.这是一个可能改变的方式 - 你如何思考你将会记住你职业生涯的其他事情.