我有一个大问题 - 即我的析构函数不删除对象,在我的代码中,当我调用时,我将粘贴在 main 下面l3.~list();
它只删除单向链表(这很好),但它不会删除 char* 名称,即使我在析构函数delete [] name;
中声明。任何想法有什么问题?
这是代码;
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
class list{
struct lista
{
int num;
char* word;
lista* next;
};
lista* head;
char* name;
public:
list(char* name1){head=NULL;name=new char[strlen(name1)+1];strcpy(name,name1);}
char getChar(int key, int index);
void setChar(int key, int index, char c);
void insert(int number,char* txt);
void remove(int number);
void print();
list(const list &o);
list& operator=(const list &x);
~list();
};
void list::insert(int number,char* txt){
lista* ptr,*tmp;
ptr=head;
lista* newlista=new lista;
newlista->num=number;
newlista->next=NULL;
newlista->word= new char[strlen(txt)+1];
strcpy(newlista->word,txt);
if(head==NULL){
head=newlista;
newlista->next=NULL;
}
else while(ptr!=NULL){
if(strcmp(txt,ptr->word)>=0){
if(ptr->next!=NULL && strcmp(txt,ptr->next->word)<=0)
{
tmp=ptr->next;
ptr->next=newlista;
newlista->next=tmp;
break;
}
else if(ptr->next!=NULL && strcmp(txt,ptr->next->word)>0)
ptr=ptr->next;
else
{
//next is empty
ptr->next=newlista;
break;
}
}
else{
//txt mniejszy niz w 1szym elemencie
newlista->next=head;
head=newlista;
break;
}
}
return;
}
void list::print(){
cout<<name<<";"<<endl;
lista *druk;
druk=head;
while(druk!=NULL){
cout<<"txt: "<<druk->word<<" | "<<"num: "<<druk->num<<endl;
druk=druk->next;
}
cout<<endl;
return;
}
void list::remove(int number){
if(head==NULL)
return;
if(head->num==number){
lista* ptr=head;
head=head->next;
delete [] ptr->word;
delete ptr;
return;
}
lista* ptr=head;
while(ptr->next!=NULL && ptr->next->num!=number)
ptr=ptr->next;
if(ptr->next==NULL){
cout<<number<<" element not found"<<endl;
return;
}
lista* todelete=ptr->next;
ptr->next=todelete->next;
delete [] todelete->word;
delete todelete;
return;
}
list::list(const list &o)
{
lista *xtr = o.head;
head=NULL;// bez tego nie działa
lista *etr=head;// nastawic etr na head?
while (xtr)
{
lista* ntr = new lista;
if (!ntr)
{
cerr << "list::CopyConstructor: Allocation memory failure!";
cerr << endl;
break;
}
ntr->num = xtr->num;
ntr->word= new char[strlen(xtr->word)+1];
strcpy(ntr->word,xtr->word);
ntr->next = NULL;
if (head)
etr->next = ntr;
else
head = ntr;
etr = ntr; // keep track of the last element in *this
xtr = xtr->next;
}
name = new char[strlen(o.name)+5];
strcpy(name,o.name);
strcat(name,"Copy");
}
list& list::operator=(const list &x)
{
if(this==&x)
return *this;
lista *etr=head;
while(etr) // removing list from this
{
etr=etr->next;
delete head;
head=etr;
}
lista *xtr=x.head;
while(xtr)
{
int copied=xtr->num;
lista *ntr= new lista;
ntr->word=new char[strlen(xtr->word)+1];
if (!ntr)
{
cerr << "list::operator=: Allocation memory failure!" << endl;
break;
}
ntr->num=copied;
strcpy(ntr->word,xtr->word);
ntr->next=NULL;
if (!head)
head = ntr;
else
etr->next = ntr;
etr = ntr; // keep track of the last element in *this
xtr = xtr->next;
}
char *name=new char[strlen(x.name)+1];
strcpy(name,x.name);
return *this;
}
list::~list()
{
cout<<"Object with name:"<<name<<" destroyed!"<<endl;
delete [] name;
lista *dtr=head;
while(dtr) // removing lista from this
{
dtr=dtr->next;
delete [] head->word;
delete head;
head=dtr;
}
}
void f();
void f(){
list o("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
o.insert(4,"kazio");
o.insert(100,"312jh31io2");
o.insert(34,"kz31231azio");
o.insert(1020,"123213312jh31io2");
o.insert(213123,"z3213io");
o.insert(1100,"zdrf312jh31io2");
o.print();
}
int main(){
list l1("lista1");
l1.insert(5,"Endian");
l1.insert(7,"Endianness");
l1.insert(100,"Hexediting");
l1.insert(34,".mil");
l1.print();
list l2(l1); // usage of CC - the same as list l2=l1;
l2.print();
l2.remove(5);
l2.print();
l1.print();
list l3("asajnment");
l3=l2=l1;
l3.print();
l2.print();
f();
l3.print();
l3.~list(); // here i use destructor on l3
l3.print(); // l3 is being printed with weird name, even though it should be destroyed
getchar();
return 0;
}
在调用析构函数后调用任何方法都会导致未定义的行为 - 它可能会也可能不会起作用,并且会产生奇怪的结果。
此外,您不应该直接调用析构函数:
- 在堆栈上分配对象时,作用域结束时会自动销毁该对象。(范围是大括号之间的东西
{}
) - 当对象在堆上分配时,使用
new
,应使用delete
销毁它。
C++析构函数不像你在 C 语言中编写的释放函数。它们更好:在 RAII 习语中,您将对象的销毁安排到它们退出范围的那一刻。这意味着您通常根本不需要释放资源:只需等到不再需要该对象(因为它无法访问),此时它会自动删除(包括调用析构函数,是的,这是可以安全调用它的唯一方法)。因此,写得好的C++在很多方面与垃圾收集语言一样好,但没有一些缺点。
获得 RAII 优势的最简单方法是使用标准容器和智能指针。在您的情况下,将lista* next
替换为 std::unique_ptr<lista> next
,char* word
替换为 std::string word
,一切都很好,根本不需要定义析构函数。
这段代码有很多错误,我不知道从哪里开始......
- 使用 std::string
- 使用 std::map 将 int 值与字符串相关联。这几乎已经可以做你想要的了。
- 不要为任何不是新的内容调用析构函数。要删除某些内容,请使用 delete/delete[],不要直接调用析构函数。如果您确实使用 new,请使用 RAII 习惯用法来管理对象,例如 std::unique_ptr 或 std::shared_ptr,以避免手动调用 delete/delete[] 并编写异常安全代码
这是一个有所改进的版本。请注意,没有一次对新建/删除的调用。
#include <iostream>
#include <string>
#include <map>
#include <cstdio>
class list
{
public:
explicit
list( std::string n ) : name( n ) {}
~list() { std::cout << "~list:" << name << std::endl; }
void list::insert(int number, std::string const& txt ){
items.insert( std::make_pair(number,txt));
}
void list::remove(int number){
items.erase( number );
}
void print( ){
std::cout << name << ";" << std::endl;
for( Items::const_iterator it = items.begin(), end = items.end(); it != end; ++it )
{
std::cout << "num: " << it->first << " | " << "txt: " << it->second << std::endl;
}
std::cout << std::endl;
}
private:
typedef std::map<int,std::string> Items;
Items items;
std::string name;
};
int main()
{
list l1( "lista1" );
l1.insert( 5, "Endian");
l1.insert( 7, "Endianness");
l1.insert( 100, "Hexediting");
l1.insert( 34, ".mil");
// extra scope so the destructor of l2 is called before call to getchar
{
list l2( l1 );
l2.remove( 5 );
l2.print();
}
l1.print();
getchar();
return 0;
}
确保销毁后不会错误访问成员的一种方法是在删除它们后将所有指针设置为 NULL。
这样,您可以放心,之后没有人可以访问您的敏感数据,因为您不再指向它。您可以再次调用析构函数而不会产生不良副作用,因为允许在 NULL 指针上调用 delete,并且不执行任何操作。
如果在删除对象后打印对象的内存状态,您将看到值保持不变,直到您不分配新对象。为程序分配的内存只能变大。删除数据时,它们不会设置为"0",只是标记为下一个 alloc 对象的空闲。
编辑:我的意思是,如果您在释放后创建一个具有未初始化值的新对象,他可以取回存储在内存中的旧值。