Từ 1 tới 10 trên tổng số 10 kết quả

Đề tài: Có ai từng bị lỗi này chưa!!!(nên xem để rút kinh nghiệm)

  1. #1
    Ngày gia nhập
    10 2007
    Bài viết
    50

    Mặc định Có ai từng bị lỗi này chưa!!!(nên xem để rút kinh nghiệm)

    trong lập trình hướng đối tượng, chắc ai cũng biết hàm hủy, bây giờ mình xét ví dụ sau:
    Code:
    #include<iostream.h>
    #include<string.h>
    class A
    {
    private:
    	int a;
    	char *str;
    public:
    	A()
    	{
    		a=0;
    		str=NULL;
    	}
    	void nhap()
    	{
    		cout<<"a:";
    		cin>>a;
    		str=new char[10];
    		cout<<"str:";
    		cin>>str;
    	}
    	void xuat()
    	{
    		cout<<a<<" "<<str;
    	}
    	A(int a1,char *str1)
    	{
    		a=a1;
    		str=strdup(str1);
    	}
    	int geta()
    	{
    		return a;
    	}
    	char* getstr()
    	{
    		return str;
    	}
    	
    	A operator=(A CopiedObject)
    	{
    		a=CopiedObject.geta();
    		str=new char[10];
    		str=strdup(CopiedObject.getstr());
    		return CopiedObject;
    	}
    	~A()
    	{
    		delete str;
    	}
    };
    
    void main()
    {
    	A a;
    	a.nhap();
    	A b;
    	b=a;
    	b.xuat();
    }
    bình thường thì chẳng thấy vấn đề nhưng khi chạy lại kô được,nhưng khi bỏ hàm hủy đi thì mọi chuyện em xuôi!!!chắc vấn đề này phải nhờ TQN giải thích giùm!!!!!

  2. #2
    Ngày gia nhập
    09 2006
    Bài viết
    711

    Thiếu copy contructor, operator= declare và implement sai.
    Đã được chỉnh sửa lần cuối bởi TQN : 23-10-2007 lúc 08:28 PM.

  3. #3
    Ngày gia nhập
    09 2006
    Bài viết
    16

    vì strdup ko phải là hàm của C++ chuẩn và trong hàm strdup thì theo mình dc biết nó sẽ dùng function malloc() để cấp phát bộ nhớ nên bạn ko thể dùng delete được mà phải dùng hàm free để giải phóng bộ nhớ.
    nothing is impossible

  4. #4
    Ngày gia nhập
    09 2006
    Bài viết
    711

    Copy constructor tui để lại để cậu tự implement, còn dưới đây là code của operator=, cậu xem lại để tìm ra lỗi sai.
    Code:
        A& operator=(const A &rhs)
        {
            if (this != &rhs)
            {
                a = rhs.geta();
                char *p = rhs.getstr();
                if (NULL != p)
                {
                    str = new char[strlen(p) + 1];
                    strcpy(str, p);
                }
                else
                {
                    str = NULL;
                }
            }
    
            return *this;
        }
    Constructor A(int a1,char *str1) của cậu cũng có thể gây crash nếu str1 là NULL, vì vậy lúc nào cũng phải kiểm tra mọi con trỏ truyền vào, lấy về, nói nôm na là luôn đặt code của mình vào tình huống xấu nhất.
    Sorry, code này của tui có 1 bug, memory leak, các bạn tìm thử memory leak ở đâu ?
    Đã được chỉnh sửa lần cuối bởi TQN : 24-10-2007 lúc 08:59 PM. Lý do: Bug memory leak !

  5. #5
    Ngày gia nhập
    10 2007
    Bài viết
    50

    TQn ơi!!, hình như TQN để tham số: A &rsh truyền vào ham có kiểu const là không ổn, nó báo lỗi: cannot convert 'this' pointer from 'const class A' to 'class A &'

  6. #6
    Ngày gia nhập
    10 2007
    Bài viết
    50

    Mặc định Có ai từng bị lỗi này chưa!!!(nên xem để rút kinh nghiệm)

    mình xin tiếp thu ý kiến trên của TQN, nhưng làm phiền bạn một chút là thằng destructor có ảnh hưởng gì đến chương trình mà khi xóa nó thi chạy được, còn để như trên thì khi chạy nó lại báo lỗi

  7. #7
    Ngày gia nhập
    09 2006
    Bài viết
    711

    Cậu đặt breakpoint hay cout 1 cái tại destructor, debug sẽ thấy. Crash do delete str 2 lần.
    Quên mất, cậu phải modify thêm:
    Code:
    int geta() const 
    {
    .....
    }
    char* getstr() const
    {
    .........
    }
    Đã được chỉnh sửa lần cuối bởi TQN : 24-10-2007 lúc 07:25 AM.

  8. #8
    Ngày gia nhập
    08 2006
    Nơi ở
    TpHCM
    Bài viết
    202

    Khi lớp của bạn sử dụng dụng cấp phát động thì bắt buộc phải có đủ bộ:
    - copy constructor
    - operator =
    - destructor

    Một số điều khác trong bài của bạn:
    Code:
    void nhap()
    	{
    		cout<<"a:";
    		cin>>a;
    
    		if (str != NULL) { 
    			delete[] str; // đã new thì trước hết phải delete, vì đây không phải là constructor nên có thể được gọi nhiều lần, tập thói quen lập trình như thế này
    			str = NULL; // nhằm giúp kiểm tra việc cấp phát thành công
    		}
    		str=new char[10]; 
    		if (str == NULL) { // cấp phát bộ nhớ thất bại ... }
    
    		
    		cout<<"str:";
    		cin>>str;
    	}
    Code:
    const char* getstr() // không cho sửa từ ngoài
    	{
    		return str;
    	}
    Code:
    	const A& operator=(const A& CopiedObject) //lấy prototype này làm chuẩn cho operator =
    	{
    		a=CopiedObject.geta();
    		str=new char[10]; //đã new thì trước đó phải huỷ, tương tự như trên
    		str=strdup(CopiedObject.getstr());
    		return CopiedObject;
    	}
    copy constructor
    Code:
    A(const A& CopiedObject) {} //lấy prototype này làm chuẩn cho copy constructor
    Đã được chỉnh sửa lần cuối bởi nguyentuan2 : 24-10-2007 lúc 08:59 AM.

  9. #9
    Ngày gia nhập
    10 2007
    Bài viết
    50

    Mặc định đây chính là hiệu ứng lề(side effect) đúng không TQN

    Code:
    b = a;

    operator= của b sẽ dc gọi, và đối số CopiedObject sẽ là 1 bản sao của a, bản sao này dc tạo ra bằng copy constructor (nghĩa là có thêm 1 đối tượng CopiedObject dc tạo ra do gọi copy constructor với đối số là a). Tuy nhiên rất tiếc lớp A ko cài copy constructor nên C++ chạy 1 copy constructor ngầm định. Đáng tiếc hơn nữa là copy constructor ngầm định này lại hơi... "chuối", thế nên thay vì sao chép toàn bộ dữ liệu của a vào CopiedObject thì nó lại dùng chung vùng dữ liệu với a.
    Sau khi kết thúc operator=, CopiedObject bị huỷ (nó chỉ là 1 biến cục bộ), do CopiedObject và a dùng chung vùng nhớ nên a đã bị huỷ ngay lúc đó. Thực tế trong câu lệnh b = a thì destructor đã dc chạy đến 2 lần, 1 lần cho CopiedObject và 1 lần cho 1 đối tượng tạm dc trả về bởi operator=. Nhưng đối tượng tạm này lại chính là CopiedObject, mà thực ra là a. Chính vì vậy, lần chạy destructor thứ nhất để xoá CopiedObject diễn ra bình thường, nhưng lần thứ 2 để xoá đối tượng tạm thì báo lỗi, vì lúc đó a đã dc xoá rồi (delete 2 lần trong C++ là lỗi).

  10. #10
    Ngày gia nhập
    09 2006
    Bài viết
    711

    Ừ, đúng rồi đó, nhưng giải thích chưa chính xác lắm. Chịu khó học thêm ASM và debug code ASM mà compiler sinh ra để hiểu rõ và chắc vấn đề hơn.
    Good job !

Các đề tài tương tự

  1. Lập trình C++ Hôm nay đi thi làm bài này gặp lỗi khó hiểu quá.Mong giải đáp để rút kinh nghiệm lần sau
    Gửi bởi nguyenlinhvuhuy trong diễn đàn Nhập môn lập trình C/C++
    Trả lời: 1
    Bài viết cuối: 30-12-2013, 07:35 PM
  2. Hà Nội Tuyển lập trình viên .NET (chấp nhận người chưa có kinh nghiệm hoặc kinh nghiệm dưới 1 năm)
    Gửi bởi nccnm trong diễn đàn Tuyển dụng - Việc làm CNTT
    Trả lời: 0
    Bài viết cuối: 20-09-2013, 10:46 AM
  3. Kinh nghiệm mua máy đo đường huyết - nên có thiết bị y tế gì trong nhà?
    Gửi bởi ceo trong diễn đàn Giới thiệu website, sản phẩm của bạn
    Trả lời: 0
    Bài viết cuối: 25-08-2013, 08:37 PM
  4. Trả lời: 1
    Bài viết cuối: 05-06-2013, 03:24 PM
  5. Định hướng nghề nghiệp: nên theo lập trình hay kinh tế :(
    Gửi bởi tao_la trong diễn đàn Kinh nghiệm CNTT
    Trả lời: 46
    Bài viết cuối: 12-07-2012, 09:06 AM

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn