我正在努力更好地理解复制构造函数。
当我在复制构造函数中创建私有(private)值的新实例时,它应该与初始值不同。
然而,事实并非如此。我没有通过引用分配值,也没有分配指针,但是当我查看调试器时,内存位置保持不变。
如果结果操作保持不变,"new"在做什么?
// 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"
最佳答案
不确定您指的是什么内存地址,但与您的声明“我也没有分配指针”相反,您的代码实际上确实分配了一个指针。事实上,其中有很多。这几乎就是它所做的一切,就是分配指针。首先在这里:
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
。
关于c++ - 为什么复制构造函数失败到 "copy",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50433271/