01/10/2018, 17:43

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)]='';
	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 ạ ?

rogp10 viết 19:44 ngày 01/10/2018

temp là local mà

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.

Hoán Vũ viết 19:56 ngày 01/10/2018

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.

viết 19:50 ngày 01/10/2018
STRING  STRING::operator+(const STRING &t)

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

Hoán Vũ viết 19:53 ngày 01/10/2018

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

STRING::~STRING()
{
	if(s!=NULL)
		delete[]s;
}
viết 19:57 ngày 01/10/2018

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

rogp10 viết 19:55 ngày 01/10/2018

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

Hoán Vũ viết 19:47 ngày 01/10/2018

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.

rogp10 viết 19:45 ngày 01/10/2018

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

Hoán Vũ viết 19:59 ngày 01/10/2018

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 ạ

Hoán Vũ viết 19:45 ngày 01/10/2018

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

viết 19:53 ngày 01/10/2018

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

codedien viết 19:45 ngày 01/10/2018

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???

viết 19:59 ngày 01/10/2018

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

Hoán Vũ viết 19:47 ngày 01/10/2018
STRING[[ không có dấu & ở đây ]]  STRING::operator+(const STRING &t)const  //<--- có chữ const ở đây
  • 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
viết 19:44 ngày 01/10/2018

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?

Hoán Vũ viết 19:47 ngày 01/10/2018
// 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];
	}
}
viết 19:46 ngày 01/10/2018

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

Hoán Vũ viết 19:55 ngày 01/10/2018

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

Bài liên quan
0