C++ 重载运算符=,类C+中的麻烦析构函数+;
我正在尝试实现一个单向列表。在命令m3=m1+m2在主功能中加倍之前,一切都非常正常。在调试时,我注意到在重载=运算符中,在销毁发生后,分配给o1对象的值消失。不知道析构函数是否有问题,或者运算符= 代码如下:C++ 重载运算符=,类C+中的麻烦析构函数+;,c++,C++,我正在尝试实现一个单向列表。在命令m3=m1+m2在主功能中加倍之前,一切都非常正常。在调试时,我注意到在重载=运算符中,在销毁发生后,分配给o1对象的值消失。不知道析构函数是否有问题,或者运算符= 代码如下: #include <iostream> using namespace std; template <class T> class Element; template <class T> class List{
#include <iostream>
using namespace std;
template <class T>
class Element;
template <class T>
class List{
friend class Element<T>;
Element<T> *head;
public:
List(){
cout<<"konstruktor"<<endl;
head=NULL;
}
~List() {
Element<T> *tmp = head;
cout << "destruktor" << endl;
while (tmp) {
//tmp = tmp->next;
delete head;
head = tmp;
}
}
friend istream &operator>>(istream &p, List<T> &o1){
Element<T>* new_ele;
Element<T>* it;
it=o1.head;
new_ele=new Element<T>;
p>>new_ele->value;
new_ele->next=NULL;
if (o1.head==NULL){
o1.head=new_ele;
}
else{
while (it->next!=NULL){
it=it->next;
}
it->next=new_ele;
}
return p;
}
friend ostream &operator<<(ostream &s, List<T> &o1){
Element<T>* it;
it=o1.head;
while(it){
s<<it->value<<" ";
it=it->next;
}
return s;
}
List <T> &operator=(const List<T> &o1){
if (this==&o1){
return *this;
}
Element<T> *it1, *it2, *itc;
this->~List();//this is the where everything goes haywire
itc=head;
it1=o1.head;
while(it1){
itc=new Element<T>;
if (!head) head=it1;
itc->next=NULL;
itc->value=it1->value;
it1=it1->next;
itc=itc->next;
}
return *this;
}
List<T> &operator+(List<T> &o1){
if(o1.head==NULL){
return *this;
}else if(head==NULL){
return o1;
}
static List<T> res=*this;
Element<T> *it;
it=res.head;
while(it->next) {
it = it->next;
}
Element <T> *o1_it=o1.head;
while(o1_it){
Element<T> *copy;
copy=new Element<T>;
copy->next=NULL;
copy->value=o1_it->value;
it->next=copy;
it=it->next;
o1_it=o1_it->next;
}
return res;
}
int length_list(){
Element<T> *it;
int count_elements=0;
it=head;
while(it->next){
count_elements++;
it=it->next;
}
return count_elements;
}
void bubblesort_List(){
Element<T> *it;
for(int i=0; this->length_list() > i;i++){
it = head;
while (it->next) {
if (it->next->value < it->value) {
T tmp = it->value;
it->value = it->next->value;
it->next->value = tmp;
}
it = it->next;
}
}
}
};
template <class T>
class Element{
friend class List<T>;
friend istream &operator>>(istream &p, List<T> &o1);
friend ostream &operator<<(ostream &s, List<T> &o1);
Element<T> *next;
T value;
public:
Element(){
next=NULL;
}
};
int main(){
List<int> m1, m2, m3;
cin>>m1>>m1>>m1;
cin>>m2;
m3=m1+m2;
m3=m1+m2;
cout<<m3<<endl;
return 0;
}
#包括
使用名称空间std;
模板
类元素;
模板
班级名单{
友元类元素;
元素*头;
公众:
列表(){
库特价值;
新建元素->下一步=空;
if(o1.head==NULL){
o1.水头=新的水头;
}
否则{
while(it->next!=NULL){
it=it->next;
}
it->next=新建;
}
返回p;
}
friend ostream&operatorvalue;
it1=it1->next;
itc=itc->next;
}
归还*这个;
}
列表和操作员+(列表和o1){
if(o1.head==NULL){
归还*这个;
}else if(head==NULL){
返回o1;
}
静态列表res=*this;
元素*it;
it=res.head;
while(it->next){
it=it->next;
}
元素*o1_it=o1.head;
while(o1_it){
元素*副本;
复制=新元素;
复制->下一步=空;
复制->值=o1\u it->值;
它->下一步=复制;
it=it->next;
o1_it=o1_it->next;
}
返回res;
}
int length_list(){
元素*it;
int count_元素=0;
它=头;
while(it->next){
计数元素++;
it=it->next;
}
返回计数元素;
}
void bubblesort_List(){
元素*it;
对于(int i=0;this->length\u list()>i;i++){
它=头;
while(it->next){
如果(it->next->valuevalue){
T tmp=it->value;
it->value=it->next->value;
it->next->value=tmp;
}
it=it->next;
}
}
}
};
模板
类元素{
好友类列表;
friend istream&operator>>(istream&p,列表&o1);
friend ostream&operatorm1>>m1>>m1;
cin>>m2;
m3=m1+m2;
m3=m1+m2;
两个主要问题
- 调用delete调用析构函数,不要显式调用~List。只需调用free_List或其他什么,然后直接调用它
- 你的析构函数坏了,不能正确释放内存
你想要:
void free_list (Element<T> * head) {
Element<T> *tmp = head;
while (tmp != null) {
head = tmp.next;
delete tmp;
tmp = head;
}
}
void free_列表(元素*头){
元素*tmp=头部;
while(tmp!=null){
head=tmp.next;
删除tmp;
tmp=头部;
}
}
这会破坏对象,而不仅仅是运行析构函数
当一个对象被销毁后,它的存储仍然存在,但那个里并没有对象。和存储交互就像有一个对象一样,存在未定义的行为
将析构函数体移动到名为clear()
的辅助函数:
修复它:
clear() {
std::cout << "clear" << std::endl;
while (head) {
Element<T>* tmp = head;
head=head->next;
delete tmp;
}
}
我把所有的东西都链接起来,以实现更简单的功能
=(&&)
和(&&)
(移动分配和移动构造)复制头并清除源代码。这是少量重复代码
=(const&)
(copy assign)使用=(&&)
(move assign)和(const&)
(copy construct)。复制节点很难,只需在一种情况下执行。复制到空实例比复制到已经存在的实例更容易
(const&)
是唯一做这项工作的。在这里,我保留了一个指向链接列表尾部指针的指针,以及一个指向要添加的下一个元素的指针
然后,我在中拼接下一个元素的副本,并更新尾部和下一个元素指针。从不显式调用析构函数。虽然存在罕见的异常,但在生活中不太可能遇到它们。
clear() {
std::cout << "clear" << std::endl;
while (head) {
Element<T>* tmp = head;
head=head->next;
delete tmp;
}
}
List& operator=(List&&o) {
if (this==&o)
return *this;
clear();
head = o.head;
o.head = nullptr;
return *this
}
List& operator=(const List &o) {
if (this== &o)
return;
*this = List(o); // call operator=(List&&) using a copy of o
return *this;
}
List(List&& o):
head(o.head)
{
o.head = nullptr;
}
List():head(nullptr) {}
// all of the work goes on here:
List(List const& o):List()
{
Element<T>* src = o.head;
Element<T>** dest = &head;
while(src) {
*dest = new Element<T>;
(*dest)->value = src->value;
(*dest)->next = nullptr;
src = src->next;
dest = &((*dest)->next);
}
}