Thắc mắc về destructor C++

Mình có code như sau

STRING&  STRING::operator+(const STRING &t)
{
	STRING temp;
	temp.s = new char[size(t) + size(s) + 1];
	int i = 0;
	int j = 0;
	while (j < size(s))
	{
		temp.s[i++] = s[j++];
	}
	j = 0;
	while (j < size(t))
	{
		temp.s[i++] = t.s[j++];
	}
	temp.s[size(t) + size(s)]='\0';
	return temp;
}

Tại sao mình return về temp rồi mà destructor vẫn chạy và xóa dữ liệu của temp vậy ạ ?

temp là local mà :smiley:

Thực sự compiler khéo sẽ bỏ qua bước copy từ local ra một đối tượng tạm (còn gọi là NRVO). C++17 bắt buộc phải bỏ bước này.

2 Likes

vậy có cách nào khắc phục không bạn, đây hàm cộng hai chuỗi trong lớp STRING mà mình tự cài đặt.
Cảm ơn bạn.

STRING  STRING::operator+(const STRING &t)

trả về 1 object hẳn luôn chứ ko trả về 1 reference tới local object

2 Likes

Vẫn bị mất bạn ơi, destructor vẫn xóa:

STRING::~STRING()
{
	if(s!=NULL)
		delete[]s;
}

mất chỗ nào ~.~ nếu là mất khi thoát main() thì đúng rồi?

Bạn có viết operator= không đó :smiley: Rule of 3 là phải viết đủ: copy, assignment, destructor.

1 Like

mình debug hết rồi bạn ơi tới bước
temp.s[size(t) + size(s)]='\0';
thằng temp vẫn là kết quả đúng f10 thêm lần nữa nó nhảy qua destructor luôn.

Bạn viết đúng operator= thì cái temp ra làm sao kệ nó :smiley: vậy bạn chưa viết assignment op rồi.

1 Like

vừa ra khỏi hàm là mất luôn ạ quay trở lại main là không bị xóa rồi ạ

Mình viết rồi bạn, cái quan trọng là debug thì nó đã bị xóa rồi và trả về một chuỗi đã bị xóa đó bạn

bưng hết code lên đây, đã xóa dấu & trong giá trị trả về của operator+ chưa??

STRING[[ không có dấu & ở đây ]]  STRING::operator+(const STRING &t)const  //<--- có chữ const ở đây

edit: code gì lạ vậy, Hàm size() trong size(t) với size(s) 1 cái nhận STRING 1 cái nhận char* à :V

2 Likes

cho mình hỏi ngu cái…
Biến temp là local thì ra khởi hàm bị xóa là phải rồi mà… phải ko ta???

nếu trả về bản copy thì nó copy ra, ko bị xóa

int& f() //hàm f trả về tham chiếu tới int
{
    int n = 2;
    return n; //n bị xóa, ko trả về n được
}

int g() //hàm g trả về int
{
    int n = 2;
    return n; //trả về 1 copy của n, an toàn
}

khi viết trả về bản copy, trình biên dịch nó khôn hơn, nó ko cần copy mà trả về thẳng n luôn, ko cần copy ra n mới rồi xóa n cũ rồi trả về n mới, ở đây nó trả về thẳng n cũ luôn. Còn trả về int& thì nó ko được thông minh cho lắm, nó cũng trả về n cũ, cũng ko copy ra n mới, nhưng lại xóa n cũ :V

1 Like
  • Giống rồi bạn ơi còn hàm size ở đây là trả về số lượng ký tự trong chuỗi mình viết 2 hàm lận nên có thể thể truyền STRING hoặc char *.
  • Vấn đề ở đây là mình debug từng dòng thì không hề sai gì cả khi tới return thì nó gọi destructor và xóa đi bộ nhớ của temp thôi bạn.
  • https://www.dreamincode.net/forums/topic/87273-returning-an-object-shutting-up-the-destructor/
  • Mình có search trên mạng thì cũng có trường hợp giống mình và mình cũng chưa tìm được hướng giải quyết. Cảm ơn bạn

dzậy quẳng hết code lên đây mới coi được lỗi chỗ nào, code lớp string trong C++ có sẵn rồi. có quý giá gì đâu mà giấu dữ vậy @_@

coi có thiếu copy ctor ko?

1 Like
// STRING.h
#ifndef STRING_H_
#define STRING_H_
#include <iostream>
using namespace std;
class STRING
{
private:
	char *s;
public:
	STRING();
	STRING(int n);
	STRING(const char*);
	void input();
	char& operator[](int i);
	STRING& operator=(const STRING&);
	friend ostream& operator<<(ostream &o, const STRING&);
	bool operator==(const STRING&);
	static void CapPhatThem(STRING&, int , int );
	static void CapPhatThem(char*&, int, int);
	friend int size(const STRING&);
	friend int size(char*);
	STRING operator+(const STRING&);
	~STRING();
};

#endif

// main.cpp
#include "STRING.h"
int main()
{
	STRING s1("abc");
	STRING s2("def");
	STRING s;
	s = s1 + s2;
	cout << s;
	return 0;
}
STRING  STRING::operator+(const STRING &t)
{
	STRING temp;
	temp.s = new char[size(t) + size(s) + 1];
	int i = 0;
	int j = 0;
	while (j < size(s))
	{
		temp.s[i++] = s[j++];
	}
	j = 0;
	while (j < size(t))
	{
		temp.s[i++] = t.s[j++];
	}
	temp.s[size(t) + size(s)]='\0';
	return temp;
}
STRING & STRING::operator=( const STRING& t)
{
	
	int n = size(t);
	if (s!= NULL)
		delete[] s;
	s = new char[n + 1];
	for (int i = 0; i < n; i++)
	{
		s[i] = t.s[i];
	}
	s[n] = '\0';
	return *this;
}
STRING::STRING(int n)
{
	s = new char[n];
	for (int i = 0; i < n; i++)
	{
		s[i] = ' ';
	}
}
STRING::STRING()
{
	s = NULL;

}
STRING::STRING(const char *t)
{
	int n=0;
	while (t[n] != '\0')
	{
		n++;
	}
	s = new char[n + 1];
	for (int i = 0; i <= n; i++)
	{
		s[i] = t[i];
	}
}
1 Like

thiếu copy ctor rồi đó. Nó như thế này:

//file .h
STRING(const STRING&);

//file .cpp
STRING::STRING(const STRING& t)
    : s{new char[size(t) + 1]}
{
   //copy t.s sang this->s
}

chắc do chạy debug nên nó vẫn phải copy ra object mới rồi xóa temp, ko trả về thẳng cái temp luôn

copy ctor giống với operator=, nhưng operator= gán khi đã có object rồi, còn copy ctor thì gán khi object chưa có gì:

STRING a = "123"; //a gọi conversion ctor nhận const char*
STRING b = a; //b gọi copy ctor vì b chưa có gì
STRING c; //c gọi default ctor
c = b; //c gọi operator= vì c đã được khởi tạo rồi

google thêm rule of three với rule of five nha, mỗi khi xài cấp phát động trong class là phải viết đủ 3/5 cái phương thức này

nếu ko viết copy ctor thì C++ nó sẽ viết dùm bạn, và nó xài shallow copy, nghĩa là nó chỉ copy đơn giản thế này: this->s = t.s;, rất “nông cạn” (shallow). Dẫn tới sau đó khi t.s bị xóa thì this->s cũng bị xóa theo. Bạn phải viết thêm copy ctor để deep copy ra mảng mới cho this->s

2 Likes

ok mình hiểu rồi cảm ơn bạn nhiều!!!

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?