【问题标题】:Why does the Copy Constuctor fail to "copy"为什么复制构造函数无法“复制”
【发布时间】:2018-05-20 09:10:03
【问题描述】:

我正在努力更好地理解复制构造函数。

当我在复制构造函数中创建私有值的新实例时,它应该不同于初始值。

但是,事实并非如此。我没有通过引用分配值,也没有分配指针,但是当我查看调试器时,内存位置保持不变。

如果结果操作保持不变,“新”会做什么?

// copy control within a template
NTree(const NTree& aOtherNTree)
{
    fKey = new T;
    fNodes[N] = new NTree<T, N>;

    fKey = aOtherNTree.fKey;
    for (int i = 0; i < N; i++)
    {
        fNodes[i] = aOtherNTree.fNodes[i];
    }

完整代码

#pragma once

#include <stdexcept>

#include "TreeVisitor.h"
#include "DynamicQueue.h"

template <class T, int N>
class NTree {
private:
    const T* fKey; // 0 for empty NTree
    NTree<T, N>* fNodes[N]; // N subtress of degree N

    NTree(); // sentinel constructor

public:
    static NTree<T, N> NIL; // sentinel

    NTree(const T& aKey); // a simple NTree with key and N subtrees of degree N

    bool isEmpty() const; // is tree empty
    const T& key() const; // get key (node value)

    // indexer (allow for result modification by client - no const in result)
    NTree& operator[](unsigned int aIndex) const;

    // tree manipulators (using constant references)
    void attachNTree(unsigned int aIndex, const NTree<T, N>& aNTree);
    const NTree& detachNTree(unsigned int aIndex);

    // depth-first traversal
    void traverseDepthFirst(const TreeVisitor<T>& aVisitor) const;

    // copy control
    NTree(const NTree& aOtherNTree)
    {
        fKey = new string;
        fNodes[N] = new NTree<string, N>;

        fKey = aOtherNTree.fKey;
        for (int i = 0; i < N; i++) {
            fNodes[i] = aOtherNTree.fNodes[i];
        }
    }

    ~NTree()
    {
        for (int i = 0; i < N; i++) {
            if (!isEmpty()) {
                if (!fNodes[i]->isEmpty()) {
                    delete fNodes[i];
                }
            }
        }
    }

    NTree& operator=(const NTree& aOtherNTree)
    {
        fKey = new T;
        fNodes[N] = new NTree<T, N>;

        fKey = aOtherNTree.fKey;
        for (int i = 0; i < N; i++) {
            fNodes[i] = aOtherNTree.fNodes[i];
        }

        return *this;
    }

    // breadth-first traversal
    void traverseBreadthFirst(const TreeVisitor<T>& aVisitor) const
    {
        DynamicQueue<const NTree<T, N>*> lQueue;
        lQueue.enqueue(this);

        while (!lQueue.isEmpty()) {
            const NTree<T, N>& head = *lQueue.top();
            lQueue.dequeue();

            aVisitor.visit(head.key());

            for (int i = 0; i < N; i++) {
                if (head.fNodes[i]->fKey != NULL) {
                    lQueue.enqueue(&head[i]);
                }
            }
        }
    }
};

// implementation

template <class T, int N>
NTree<T, N> NTree<T, N>::NIL;

// sentinel constructor
template <class T, int N>
NTree<T, N>::NTree()
{
    fKey = (T*)0;
    for (int i = 0; i < N; i++)
        fNodes[i] = &NIL;
}

// node constructor
template <class T, int N>
NTree<T, N>::NTree(const T& aKey)
{
    fKey = &aKey;
    for (int i = 0; i < N; i++)
        fNodes[i] = &NIL;
}

// isEmpty
template <class T, int N>
bool NTree<T, N>::isEmpty() const
{
    return this == &NIL;
}

// key
template <class T, int N>
const T& NTree<T, N>::key() const
{
    if (!isEmpty())
        return *fKey;
    else
        throw std::domain_error("Empty NTree.");
}

// indexer
template <class T, int N>
NTree<T, N>& NTree<T, N>::operator[](unsigned int aIndex) const
{
    if (isEmpty())
        throw std::domain_error("Empty NTree!");

    if (aIndex < N && fNodes[aIndex] != &NIL) {
        return *fNodes[aIndex]; // return reference to subtree
    }
    else
        throw std::out_of_range("Illegal subtree index!");
}

// tree manipulators
template <class T, int N>
void NTree<T, N>::attachNTree(unsigned int aIndex, const NTree<T, N>& aNTree)
{
    if (isEmpty())
        throw std::domain_error("Empty NTree!");

    if (aIndex < N) {
        if (fNodes[aIndex] != &NIL)
            throw std::domain_error("Non-empty subtree present!");

        fNodes[aIndex] = (NTree<T, N>*)&aNTree;
    }
    else
        throw std::out_of_range("Illegal subtree index!");
}

template <class T, int N>
const NTree<T, N>& NTree<T, N>::detachNTree(unsigned int aIndex)
{
    if (isEmpty())
        throw std::domain_error("Empty NTree!");

    if ((aIndex < N) && fNodes[aIndex] != &NIL) {
        const NTree<T, N>& Result = *fNodes[aIndex]; // obtain reference to subtree
        fNodes[aIndex] = &NIL; // set to NIL
        return Result; // return subtree (reference)
    }
    else
        throw std::out_of_range("Illegal subtree index!");
}

template <class T, int N>
void NTree<T, N>::traverseDepthFirst(const TreeVisitor<T>& aVisitor) const
{
    // visit every subtree (no invisit)
    if (!isEmpty()) {
        aVisitor.preVisit(key());
        for (unsigned int i = 0; i < N; i++) {
            fNodes[i]->traverseDepthFirst(aVisitor);
        }
        aVisitor.postVisit(key());
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "NTree.h"

【问题讨论】:

    标签: c++ tree copy-constructor deep-copy


    【解决方案1】:

    不确定您指的是什么内存地址,但与您的声明相反“我也没有分配指针”,您的代码实际上确实分配了一个指针。事实上,他们中的许多人。这几乎就是它所做的一切,就是分配指针。首先在这里:

    fKey = new T;
    

    这是一个指针赋值。是这样的:

    fNodes[N] = new NTree<T, N>;
    

    这也恰好是对数组越界元素的赋值。也就是说,fNodes 是一个由 N 指针组成的数组,fNodes[N-1] 是该数组中的最后一个元素(指针),而fNodes[N] 超出了范围。

    这也是一个指针赋值:

    fKey = aOtherNTree.fKey;
    

    这也是内存泄漏,因为您现在已经覆盖了函数前面对new T 的调用返回的值。因此无法访问,也无法释放该对象。

    最后,你的 for 循环由 N 个指针赋值组成。

    for (int i = 0; i < N; i++)
    {
        fNodes[i] = aOtherNTree.fNodes[i];
    }
    

    您只是将指针从aOtherNTree.fNodes 复制到fNodes

    【讨论】:

    • 通常你在创建一个拷贝构造函数时想要的是你希望所有成员的值与前一个对象相同,但在不同的内存地址。您不希望两个对象持有指向同一个地址的指针,因为可能析构函数在该指针上调用 delete 并且您删除了两次内存。
    • @MivVG 这就是我想要做的,但正如你从我的代码 sn-p 中看到的那样,它并不顺利。
    • 您必须按照here 的说明进行操作。基本上在你的情况下,这变成*fKey = *other.fKey
    • @MivVG 我试过了,但没有用。我查看了您发送的文档,他们这样做 // 为我们的副本分配内存 m_data = new char[m_length]; // 复制 (int i=0; i
    • 对于fNodes,你做的很好,但是你在复制fKey的时候还是在复制一个指针
    猜你喜欢
    • 2012-11-28
    • 2012-09-15
    • 2017-03-26
    • 1970-01-01
    • 2021-05-14
    • 1970-01-01
    • 2012-12-18
    • 2020-01-14
    • 2012-02-28
    相关资源
    最近更新 更多