2009-03-19 44 views
10

Tôi tình cờ gặp đoạn mã này dường như đã bị phá vỡ hoàn toàn đối với tôi, nhưng điều đó xảy ra là thisnull. Tôi chỉ không nhận được như thế nào điều này có thể nullnếu (! This) {return false; }

nó là bên trong một phương pháp gọi bình thường như

myObject->func(); 

bên MyObject::func() chúng tôi có

if (!this) { return false; } 

là có cách nào tôi có thể có dòng đầu tiên để ném một NullPointerException thay vì đi vào bên trong phương thức null (?)?

+0

Đây có phải là .net cụ thể không? - bạn có thể muốn thay đổi thẻ, rất nhiều người dùng C++ sẽ lọc ra .net –

+1

NullPointerException khiến tôi tin rằng đây không phải là câu hỏi C++. C#? – Tom

Trả lời

22

Nếu bạn có:

MyObject *o = NULL; 

o->func(); 

gì sẽ xảy ra tiếp theo phụ thuộc vào việc func là ảo. Nếu có, sau đó nó sẽ sụp đổ, bởi vì nó cần một đối tượng để có được vtable từ. Nhưng nếu nó không phải là ảo cuộc gọi tiến hành với con trỏ này thiết lập để NULL. Tôi tin rằng tiêu chuẩn nói rằng đây là "hành vi không xác định", vì vậy bất cứ điều gì có thể xảy ra, nhưng trình biên dịch điển hình chỉ tạo ra mã để không kiểm tra xem con trỏ là NULL hay chưa. Một số thư viện nổi tiếng dựa vào hành vi mà tôi mô tả: MFC có một hàm gọi là SafeGetHandle có thể được gọi trên một con trỏ null và trả về NULL trong trường hợp đó.

Bạn có thể muốn viết một hàm helper tái sử dụng:

void CheckNotNull(void *p) 
{ 
    if (p == NULL) 
     throw NullPointerException(); 
} 

Sau đó bạn có thể sử dụng vào lúc bắt đầu của một hàm để kiểm tra tất cả các đối số của nó, bao gồm this:

CheckNotNull(this); 
+0

Chỉ cần làm rõ mọi thứ ... dereferencing NULL là hành vi không xác định theo tiêu chuẩn. MFC thực sự không nên phụ thuộc vào điều này. Nếu nó được thực hiện xác định, mọi thứ sẽ khác nhau. Rất có thể đây là một nỗ lực kém trong việc "sửa chữa" một điều kiện chủng tộc. –

+0

tôi nghĩ rằng câu chuyện này là thích hợp: http://www.gotw.ca/conv/002.htm –

+0

Thay thế đạo đức cho câu chuyện: thực hiện CheckNotNull và làm cho nó ném một ngoại lệ với thông điệp "Đừng là một thằng khốn, Bob ! " –

1
if(this == null) 
    throw new NullPointerException; 
if(!this) 
    return false; 
+0

Tại sao bạn lại ném một con trỏ tới ngoại lệ? –

+0

Và tại sao thử nghiệm này hai lần cho NULL? – Eclipse

+0

Mã của bạn trông giống C#, phải không? – mmmmmmmm

-1

này = = null chỉ nên xảy ra nếu bạn đang gọi một phương thức trên một đối tượng đã xóa, hoặc nếu một cái gì đó được ghi vào bộ nhớ mà nó không nên (và ghi đè lên con trỏ của đối tượng này cụ thể).

Bạn nên điều tra những gì thực sự sai với mã của bạn thay vì cố gắng làm việc xung quanh nó như thế này.

+0

Xóa đối tượng không đặt con trỏ thành rỗng. –

+0

+1 cho bình luận của Mark Ransom. – Tom

0

con trỏ này có thể trở thành vô giá trị trong trường hợp như thế này:

class Test 
{ 

public: 
    bool f(); 

private: 
    int m_i; 
}; 


bool Test::f() 
{ 
    if(!this) 
    { 
     return false; 
    } 

    m_i = 0; 
    return true; 

} 


int main(int argc, char **argv) 
{ 
    Test* p = new Test; 
    delete p; 
    p = NULL; 

    p->f(); 
} 

Tôi đoán ai đó đã làm một cách nhanh chóng hack để tránh cho ngoại lệ truy cập vi phạm.

+0

Tôi chỉ ngạc nhiên rằng điều đó không sụp đổ ngay sau khi nó tryies để gọi f ... Tôi có nghĩa là nếu p là NULL, p-> bất cứ điều gì nên seg-fault ... –

1

Có thể cho this bị vô hiệu. Tôi nghi ngờ rằng mã này đang cố gắng phát hiện một điều kiện chủng tộc, nơi đối tượng chưa được hoàn thành đang được khởi tạo hoặc đã bị xóa.

+0

bạn không thể thay đổi "này" . đó là một rvalue. (= "this" không phải là một đối tượng). bạn có thể nghĩ về nó như thế này, hãy tưởng tượng "self" là con trỏ này: T * self_ = this; #define self (self_ + 0) // bạn không thể làm (self + 0) = ... –

+0

Ugh, bạn nói đúng.Tôi có nghĩa là để nói "nhưng nó không thể được ghi vào". –

1

(this == NULL) là hành vi không xác định theo tiêu chuẩn. Tôi nghĩ rằng bạn nên loại bỏ việc kiểm tra này :)

Giả sử chúng ta thực hiện cuộc gọi như sau:

((CSomeClass*) 0)->method(); 

Các hành vi đã được xác định, vì vậy tại sao bận tâm làm việc kiểm tra cho NULL == này trong CSomeClass :: phương pháp?

CHỈNH SỬA: Tôi giả sử rằng trình biên dịch của bạn sẽ xử lý (0 == this) nếu bạn không sử dụng biến thành viên, nhưng nó sẽ tìm thấy con trỏ bảng ảo? Trong trường hợp này, lớp học của bạn không thể sử dụng polymoprhism.

+0

Một lý do cho việc đăng ký là thực thi tiêu chuẩn đúng cách, nếu trình biên dịch của bạn không làm điều đó cho bạn. –

+0

tôi sẽ không gọi nó trên NULL ở nơi đầu tiên, sau đó kiểm tra sẽ không cần thiết ở tất cả. hoặc - khi tôi kiểm tra - sau đó vào thời gian gọi. tại sao callee nên lo lắng khi người gọi thực hiện những điều không thể như vậy? một con trỏ thông minh tốt có chứa một khẳng định cho tình hình đó là tất cả các quyền tôi nghĩ rằng –

+0

có, khẳng định (obj) trong mã (không phải trong phương pháp) hoặc trong con trỏ thông minh giúp chúng tôi phát hiện vấn đề. nói chung tôi thấy nhiều nhà phát triển không mặc dù điều gì sẽ không bao giờ xảy ra và nên được khẳng định và những gì cần được kiểm tra. – bayda

2

Một cách để bẫy các loại lỗi này (theo thiết kế) đang sử dụng lớp trình bao bọc con trỏ (giống như một shared_ptr) mà ném khi tạo bằng đối số con trỏ null. Nó có thể cũng bị ném khi bị dereferenced, nhưng đó là một chút muộn - tốt hơn không có gì, tôi đoán.

+0

tôi nghĩ rằng lần đầu tiên tăng :: shared_ptr sẽ ném. nhưng sau khi xem xét nó, tôi phải xóa câu trả lời của tôi, bởi vì nó không rõ ràng: (rõ ràng nó là để thực hiện cho dù một cái gì đó được ném hay không. Tuy nhiên, trong GCC của tôi tôi nhận được một sự thất bại khẳng định - tốt hơn so với không có gì :) –

Các vấn đề liên quan