代码之家  ›  专栏  ›  技术社区  ›  eKKiM

在使用复制构造函数后双重释放子对象

  •  4
  • eKKiM  · 技术社区  · 7 年前

    我很难弄清楚为什么一个物体被破坏了两次。

    如果我创建一个类(B)的对象,其中包含另一个类(A)的对象,我复制这个对象。复制的对象被销毁两次。尽管看起来像这样。我无法计算出这个输出。

    我已经创建了以下内容(最少?)引发我问题的例子:

    #include <stdio.h>
    #include <stdint.h>
    
    template <class T>
    class A
    {
    public:
        A()
        {
            myCtr = ++ctr;
            printf("class A default Constructor - object id: %u\n", myCtr);
        }
    
        A(const A<T> &a2) {
            myCtr = ++ctr;
            printf("class A copy constructor - object id: %u\n", myCtr);
    
        }
    
        ~A()
        {
            printf("class A destructor - object id: %u\n", myCtr);
        }
    
        void add(T item) {
            /* Irrelevant */
        }
    
    private:
        uint64_t myCtr;
        static uint64_t ctr;
    };
    
    class B
    {
    public:
        B() {
    
        }
    
        B(char * input, uint32_t len) {
            for (uint32_t i = 0; i < len; i++)
            {
                characters.add(input[i]);
            }
        }
    
        B(const B &b2) {
            characters = A<char>(b2.characters);
        }
    
        ~B() {
    
        }
    
    
    private:
        A<char> characters;
    };
    
    template <class T>
    uint64_t A<T>::ctr = 0;
    
    int main(int argc, char *argv[]) {
        B b1 = B((char *)"b1", 2);
        B b2 = B(b1);
    
        return 0;
    }
    

    这将产生以下输出:

    class A default Constructor - object id: 1
    class A default Constructor - object id: 2
    class A copy constructor - object id: 3
    class A destructor - object id: 3
    class A destructor - object id: 3
    class A destructor - object id: 1
    

    对象ID 3被销毁两次,而对象ID 2根本没有被销毁。

    我正在使用以下编译器: 微软(R)C/C++优化编译器版本19.1426427.4

    以防你投反对票。请说明原因。我很乐意尝试改进我的问题。

    2 回复  |  直到 7 年前
        1
  •  5
  •   Yakk - Adam Nevraumont    7 年前

    你需要遵循 rule of 5 . 如果您实现了一个非平凡的析构函数copy/move assign/construct,那么您必须实现全部5个,或者给出一个不实现的好理由,或者删除它们。

    您实现了destory和copy ctor。你忽略了另外三个。添加它们。

    还有什么 characters = A<char>(b2.characters); 您的复制ctor调用复制分配。你不跟踪它,这就是为什么你的计数被取消的原因。你在柜台上分配。

        2
  •  3
  •   Drew Dormann    7 年前

    困惑来自这一行。

    characters = A<char>(b2.characters);
    

    默认生成的分配运算符 将对象3复制到对象2,包括 myCtr .

    MycTR 不是 const 因此,它可能在其生命周期内发生变化。如果您需要一个值保持不变,请使其 康斯特 .

    这是您的类的一个版本,它将按照您期望的方式运行。

    template <class T>
    class A
    {
    public:
        A()
            : myCtr( ++ctr )
        {
            printf("class A default Constructor - object id: %u\n", myCtr);
        }
    
        A(const A<T> &a2)
            : myCtr( ++ctr )
        {
            printf("class A copy constructor - object id: %u\n", myCtr);
    
        }
    
        A<T>& operator=(const A<T> &a2) {
            // Copy what's needed from a2 here.
            return *this;
        }
    
        ~A()
        {
            printf("class A destructor - object id: %u\n", myCtr);
        }
    
        void add(T item) {
            /* Irrelevant */
        }
    
    private:
        const uint64_t myCtr;
        static uint64_t ctr;
    };