拷贝构造函数和赋值运算符的正确写法
Correct way to write copy constructor and assignment operator
我有一个数据结构,我有函数 Ins(key, value) 将它们插入到数据结构中。我正在尝试编写复制构造函数和赋值运算符。我不知道只有这部分代码是否足够我还可以添加其余部分。这段代码不知何故有错误。
问题出在 Ins(temp -> m_Key, temp -> m_Val);两次。
CHash(const CHash & src)
{
m_Table = new TItem * [src.m_Size];
TItem * temp = src.m_FirstOrder;
while (temp != NULL)
{
Ins(temp -> m_Key, temp -> m_Val);
temp = temp -> m_NextOrder;
}
}
CHash & operator = (const CHash & src)
{
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
TItem * tmp = temp;
temp = temp -> m_NextOrder;
delete tmp;
}
delete [] m_Table;
m_Table = new TItem * [src.m_Size];
TItem * tmp1 = src.m_FirstOrder;
while (tmp1 != NULL)
{
Ins(tmp1 -> m_Key, tmp1 -> m_Val);
tmp1 = tmp1 -> m_NextOrder;
}
}
我在 main 中尝试这个并遇到段错误。
CHash hashtable(100);
CHash hash2(50);
hash2 = hashtable;
hashtable.printAll();
hash2.printAll();
CHash b(hash2);
b.printAll();
这是完整的代码:
#include <string>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
struct TItem {
TItem(string key, string val, TItem* nextHash,TItem* nextOrd, TItem * prevOrd)
:m_Key(key),m_Val(val),m_NextHash(nextHash),m_NextOrder(nextOrd),m_PrevOrder(prevOrd){}
string m_Key,m_Val;
TItem * m_NextHash, * m_NextOrder, * m_PrevOrder;
};
class CHash{
public:
CHash (int m) : m_Table(NULL),m_Size(m),m_FirstOrder(NULL),m_LastOrder(NULL)
{
m_Table = new TItem * [m];
for (int i = 0; i < m; i++)
m_Table[i] = NULL;
}
~CHash()
{
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
TItem * tmp = temp;
temp = temp -> m_NextOrder;
delete tmp;
}
delete [] m_Table;
}
bool IsSet(string key)
{
TItem * temp = m_Table[hashFn(key)];
if (temp == NULL)
{
return false;
}
while (temp != NULL)
{
if (temp -> m_Key == key)
{
return true;
}
temp = temp -> m_NextHash;
}
return false;
}
CHash(const CHash & src)
{
m_Size = src.m_Size;
m_Table = new TItem * [src.m_Size];
for (int i = 0; i < src.m_Size; i++)
m_Table[i] = NULL;
TItem * temp = src.m_FirstOrder;
while (temp != NULL)
{
Ins(temp -> m_Key, temp -> m_Val);
temp = temp -> m_NextOrder;
}
}
CHash & operator = (const CHash & src)
{
m_Size = src.m_Size;
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
TItem * tmp = temp;
temp = temp -> m_NextOrder;
delete tmp;
}
delete [] m_Table;
m_Table = new TItem * [src.m_Size];
for (int i = 0; i < src.m_Size; i++)
m_Table[i] = NULL;
TItem * tmp1 = src.m_FirstOrder;
while (tmp1 != NULL)
{
Ins(tmp1 -> m_Key, tmp1 -> m_Val);
tmp1 = tmp1 -> m_NextOrder;
}
}
bool Ins(const string & key, const string & val)
{
string help = key;
if (IsSet(help))
return false;
//first element added ever
if (m_FirstOrder == NULL)
{
TItem * tmp01 = new TItem(key, val, NULL, NULL, NULL);
m_Table[hashFn(help)] = tmp01;
m_FirstOrder = m_LastOrder = tmp01;
}
else
{
TItem * temp = m_Table[hashFn(help)];
//first added to that hash
if (temp == NULL)
{
TItem * tmp02 = new TItem(key, val, NULL, NULL, m_LastOrder);
m_Table[hashFn(help)] = tmp02;
m_LastOrder -> m_NextOrder = tmp02;
m_LastOrder = tmp02;
}
else
{
while (temp -> m_NextHash != NULL)
{
temp = temp -> m_NextHash;
}
TItem * tmp03 = new TItem(key, val, NULL, NULL, m_LastOrder);
temp -> m_NextHash = tmp03;
m_LastOrder -> m_NextOrder = tmp03;
m_LastOrder = tmp03;
}
}
return true;
}
bool Del (const string & key)
{
string help = key;
if (!IsSet(help))
return false;
TItem * temp = m_Table[hashFn(help)];
if (temp == NULL)
return false;
while (temp != NULL)
{
if (temp -> m_Key == key)
break;
temp = temp -> m_NextHash;
}
if (temp == NULL)
return false;
if (m_FirstOrder == temp)
m_FirstOrder = m_FirstOrder -> m_NextOrder;
else
temp -> m_PrevOrder -> m_NextOrder = temp -> m_NextOrder;
if (m_LastOrder == temp)
m_LastOrder = m_LastOrder -> m_PrevOrder;
m_Table[hashFn(help)] = temp -> m_NextHash;
delete temp;
return true;
}
template <typename func>
void ForEach(func f)
{
}
void printAll()
{
cout << "PRINTING" << endl;
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
cout << " : " << temp -> m_Val << " : ";
temp = temp -> m_NextOrder;
}
cout << endl;
}
private:
TItem ** m_Table;
unsigned int m_Size;
TItem * m_FirstOrder, * m_LastOrder;
unsigned int hashFn(string & str){
std::hash<std::string> hash_fn;
return hash_fn(str)%m_Size;
}
};
int main(int argc, char** argv) {
CHash hashtable(100);
CHash hash2(50);
hashtable.Ins("h1","car");
assert ( !hashtable.Ins("h1","phone"));
hashtable.Ins("h2","field");
hashtable.Ins("h3","house");
hashtable.Ins("h4","tree");
hashtable.printAll();
assert ( hashtable.Del("h3") );
assert ( !hashtable.Ins("h4","tree") );
assert(!hashtable.Del("h4d"));
assert(hashtable.Del("h1"));
assert(!hashtable.Del("h3"));
assert(!hashtable.Del("h1"));
hash2 = hashtable;
hashtable.printAll();
hash2.printAll();
CHash b(hash2);
b.printAll();
hashtable.ForEach([](TItem * it ){
cout<<it->m_Key<<" - "<<it->m_Val<<endl;
});
return 0;
}
我运行它是这样的:g++ -std=c++11 -g filename.cpp
我发现你的代码有几个问题。
- 赋值运算符不 return
*this
.
- 复制构造函数没有初始化
m_FirstOrder
和 m_LastOrder
。
- 大量复制粘贴使代码难以阅读并且error-prone。
如果我们解决问题,我们会得到:
class CHash{
public:
CHash (int m)
{
initialize(m);
}
~CHash()
{
finalize();
}
CHash(const CHash & src)
{
initialize(src.m_Size);
copy(src.m_FirstOrder);
}
CHash & operator = (const CHash & src)
{
if (&src == this)
return;
finalize();
initialize(src.m_Size);
copy(src.m_FirstOrder);
return *this;
}
...
private:
...
void initialize(int m)
{
m_Size = m;
m_Table = new TItem * [m];
for (int i = 0; i < m; i++)
m_Table[i] = NULL;
m_FirstOrder = NULL;
m_LastOrder = NULL;
}
void finalize()
{
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
TItem * tmp = temp;
temp = temp -> m_NextOrder;
delete tmp;
}
delete [] m_Table;
}
void copy(TItem *src)
{
while (src != NULL)
{
Ins(src -> m_Key, src -> m_Val);
src = src -> m_NextOrder;
}
}
};
不过我想知道,为什么你不使用 nullptr
而不是 NULL
和 std::vector<TItem*>
而不是 TItem**
...
我有一个数据结构,我有函数 Ins(key, value) 将它们插入到数据结构中。我正在尝试编写复制构造函数和赋值运算符。我不知道只有这部分代码是否足够我还可以添加其余部分。这段代码不知何故有错误。
问题出在 Ins(temp -> m_Key, temp -> m_Val);两次。
CHash(const CHash & src)
{
m_Table = new TItem * [src.m_Size];
TItem * temp = src.m_FirstOrder;
while (temp != NULL)
{
Ins(temp -> m_Key, temp -> m_Val);
temp = temp -> m_NextOrder;
}
}
CHash & operator = (const CHash & src)
{
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
TItem * tmp = temp;
temp = temp -> m_NextOrder;
delete tmp;
}
delete [] m_Table;
m_Table = new TItem * [src.m_Size];
TItem * tmp1 = src.m_FirstOrder;
while (tmp1 != NULL)
{
Ins(tmp1 -> m_Key, tmp1 -> m_Val);
tmp1 = tmp1 -> m_NextOrder;
}
}
我在 main 中尝试这个并遇到段错误。
CHash hashtable(100);
CHash hash2(50);
hash2 = hashtable;
hashtable.printAll();
hash2.printAll();
CHash b(hash2);
b.printAll();
这是完整的代码:
#include <string>
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
struct TItem {
TItem(string key, string val, TItem* nextHash,TItem* nextOrd, TItem * prevOrd)
:m_Key(key),m_Val(val),m_NextHash(nextHash),m_NextOrder(nextOrd),m_PrevOrder(prevOrd){}
string m_Key,m_Val;
TItem * m_NextHash, * m_NextOrder, * m_PrevOrder;
};
class CHash{
public:
CHash (int m) : m_Table(NULL),m_Size(m),m_FirstOrder(NULL),m_LastOrder(NULL)
{
m_Table = new TItem * [m];
for (int i = 0; i < m; i++)
m_Table[i] = NULL;
}
~CHash()
{
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
TItem * tmp = temp;
temp = temp -> m_NextOrder;
delete tmp;
}
delete [] m_Table;
}
bool IsSet(string key)
{
TItem * temp = m_Table[hashFn(key)];
if (temp == NULL)
{
return false;
}
while (temp != NULL)
{
if (temp -> m_Key == key)
{
return true;
}
temp = temp -> m_NextHash;
}
return false;
}
CHash(const CHash & src)
{
m_Size = src.m_Size;
m_Table = new TItem * [src.m_Size];
for (int i = 0; i < src.m_Size; i++)
m_Table[i] = NULL;
TItem * temp = src.m_FirstOrder;
while (temp != NULL)
{
Ins(temp -> m_Key, temp -> m_Val);
temp = temp -> m_NextOrder;
}
}
CHash & operator = (const CHash & src)
{
m_Size = src.m_Size;
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
TItem * tmp = temp;
temp = temp -> m_NextOrder;
delete tmp;
}
delete [] m_Table;
m_Table = new TItem * [src.m_Size];
for (int i = 0; i < src.m_Size; i++)
m_Table[i] = NULL;
TItem * tmp1 = src.m_FirstOrder;
while (tmp1 != NULL)
{
Ins(tmp1 -> m_Key, tmp1 -> m_Val);
tmp1 = tmp1 -> m_NextOrder;
}
}
bool Ins(const string & key, const string & val)
{
string help = key;
if (IsSet(help))
return false;
//first element added ever
if (m_FirstOrder == NULL)
{
TItem * tmp01 = new TItem(key, val, NULL, NULL, NULL);
m_Table[hashFn(help)] = tmp01;
m_FirstOrder = m_LastOrder = tmp01;
}
else
{
TItem * temp = m_Table[hashFn(help)];
//first added to that hash
if (temp == NULL)
{
TItem * tmp02 = new TItem(key, val, NULL, NULL, m_LastOrder);
m_Table[hashFn(help)] = tmp02;
m_LastOrder -> m_NextOrder = tmp02;
m_LastOrder = tmp02;
}
else
{
while (temp -> m_NextHash != NULL)
{
temp = temp -> m_NextHash;
}
TItem * tmp03 = new TItem(key, val, NULL, NULL, m_LastOrder);
temp -> m_NextHash = tmp03;
m_LastOrder -> m_NextOrder = tmp03;
m_LastOrder = tmp03;
}
}
return true;
}
bool Del (const string & key)
{
string help = key;
if (!IsSet(help))
return false;
TItem * temp = m_Table[hashFn(help)];
if (temp == NULL)
return false;
while (temp != NULL)
{
if (temp -> m_Key == key)
break;
temp = temp -> m_NextHash;
}
if (temp == NULL)
return false;
if (m_FirstOrder == temp)
m_FirstOrder = m_FirstOrder -> m_NextOrder;
else
temp -> m_PrevOrder -> m_NextOrder = temp -> m_NextOrder;
if (m_LastOrder == temp)
m_LastOrder = m_LastOrder -> m_PrevOrder;
m_Table[hashFn(help)] = temp -> m_NextHash;
delete temp;
return true;
}
template <typename func>
void ForEach(func f)
{
}
void printAll()
{
cout << "PRINTING" << endl;
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
cout << " : " << temp -> m_Val << " : ";
temp = temp -> m_NextOrder;
}
cout << endl;
}
private:
TItem ** m_Table;
unsigned int m_Size;
TItem * m_FirstOrder, * m_LastOrder;
unsigned int hashFn(string & str){
std::hash<std::string> hash_fn;
return hash_fn(str)%m_Size;
}
};
int main(int argc, char** argv) {
CHash hashtable(100);
CHash hash2(50);
hashtable.Ins("h1","car");
assert ( !hashtable.Ins("h1","phone"));
hashtable.Ins("h2","field");
hashtable.Ins("h3","house");
hashtable.Ins("h4","tree");
hashtable.printAll();
assert ( hashtable.Del("h3") );
assert ( !hashtable.Ins("h4","tree") );
assert(!hashtable.Del("h4d"));
assert(hashtable.Del("h1"));
assert(!hashtable.Del("h3"));
assert(!hashtable.Del("h1"));
hash2 = hashtable;
hashtable.printAll();
hash2.printAll();
CHash b(hash2);
b.printAll();
hashtable.ForEach([](TItem * it ){
cout<<it->m_Key<<" - "<<it->m_Val<<endl;
});
return 0;
}
我运行它是这样的:g++ -std=c++11 -g filename.cpp
我发现你的代码有几个问题。
- 赋值运算符不 return
*this
. - 复制构造函数没有初始化
m_FirstOrder
和m_LastOrder
。 - 大量复制粘贴使代码难以阅读并且error-prone。
如果我们解决问题,我们会得到:
class CHash{
public:
CHash (int m)
{
initialize(m);
}
~CHash()
{
finalize();
}
CHash(const CHash & src)
{
initialize(src.m_Size);
copy(src.m_FirstOrder);
}
CHash & operator = (const CHash & src)
{
if (&src == this)
return;
finalize();
initialize(src.m_Size);
copy(src.m_FirstOrder);
return *this;
}
...
private:
...
void initialize(int m)
{
m_Size = m;
m_Table = new TItem * [m];
for (int i = 0; i < m; i++)
m_Table[i] = NULL;
m_FirstOrder = NULL;
m_LastOrder = NULL;
}
void finalize()
{
TItem * temp = m_FirstOrder;
while (temp != NULL)
{
TItem * tmp = temp;
temp = temp -> m_NextOrder;
delete tmp;
}
delete [] m_Table;
}
void copy(TItem *src)
{
while (src != NULL)
{
Ins(src -> m_Key, src -> m_Val);
src = src -> m_NextOrder;
}
}
};
不过我想知道,为什么你不使用 nullptr
而不是 NULL
和 std::vector<TItem*>
而不是 TItem**
...