2015-12-21 18 views
24

Giả sử đoạn mã sau:Có thể có lỗi phân đoạn từ tham chiếu không?

Foo & foo = getFoo(); 
foo.attr; // 100% safe access? 

Nếu foo là một con trỏ, tôi sẽ kiểm tra nếu nó là NULL, tuy nhiên vì nó là một tài liệu tham khảo, kiểm tra như vậy là hưởng ứng nhiệt liệt. Những gì tôi muốn biết là nếu nó có thể mess up với một tham chiếu của đối tượng như vậy mà nó sẽ làm cho truy cập thuộc tính của nó không an toàn.

Tôi đã thử một số ví dụ như cố gắng truyền NULL đến một đối tượng Foo nhưng tôi đã gặp phải lỗi biên dịch. Tôi chỉ muốn chắc chắn rằng đoạn mã trên luôn an toàn, và rằng không thể có một phép màu đen bên trong có thể là C++ mà tôi nên biết.

Từ câu trả lời của Benjamin, tôi có thể tạo mã ví dụ nơi tôi nhận được segmentation fault từ tham chiếu, do đó, nó trả lời câu hỏi của tôi. Tôi sẽ dán mã của tôi chỉ trong trường hợp ai đó quan tâm đến tương lai:

#include <iostream> 
using namespace std; 

class B 
{ 
    public: 
    int x; 
    B() {x = 5;} 
}; 
class A 
{ 
    public: 
    void f() 
    { 
     b = *(B*)NULL; 
    } 
    B & getB() 
    { 
     return b; 
    } 

    B b; 
}; 

int main() 
{ 
    A a; 
    a.f(); 

    cout << a.getB().x << endl; 
    return 0; 
} 
+0

Các 'getFoo' chức năng, để trả lời câu hỏi của bạn tốt hơn. –

+0

Trong vấn đề thực sự của tôi, 'getFoo' có hàng trăm dòng mã, và đối tượng mà nó trả về có thể được sửa đổi bởi hàng trăm chủ đề ... Vì vậy, không, không thể tạo một ví dụ về' getFoo'. – Kira

+1

@Kira: Lưu ý rằng segfault của bạn gần như chắc chắn từ câu lệnh 'b = * (B *) NULL;' trong hàm 'f()'. Không phải từ 'a.getB(). X' trong' main'. –

Trả lời

28

Có, có thể.

Foo& Fr = *(Foo*)nullptr; 

Về mặt kỹ thuật, đây là hành vi chưa xác định để bỏ qua con trỏ đó. Nhưng rất có thể sẽ không dẫn đến bất kỳ lỗi nào có thể quan sát được. Điều này có thể sẽ mặc dù:

Fr.attr = 10; 

Tuy nhiên, như Jonathan Wakely chỉ ra trong các nhận xét, không có lý do gì để bạn kiểm tra trường hợp như thế này. Nếu một hàm trả về tham chiếu không hợp lệ, hàm đó bị hỏng và cần phải được sửa. Mã sử ​​dụng của bạn không bị hỏng vì giả định rằng tham chiếu hợp lệ. Tuy nhiên, một tham chiếu hợp lệ có thể trở thành không hợp lệ (mặc dù không phải là null) trong mã hoàn toàn hợp pháp, như được đề cập trong câu trả lời của David Schwartz. Nhưng không có cách nào để bạn kiểm tra điều này. Bạn chỉ cần biết trong trường hợp nào nó có thể xảy ra, và sau đó ngừng sử dụng tham chiếu.

+1

Trong trường hợp này, trường hợp này chỉ có thể xảy ra trong mã có lỗi ở nơi khác. Chắc chắn trường hợp truy cập vào đối tượng được tham chiếu là lỗi duy nhất ít nhất cũng quan trọng và ít nhất đáng được đề cập đến. –

+1

@DavidSchwartz: Chắc chắn rồi. Tôi upvoted câu trả lời của bạn. –

16

Có thể có tham chiếu đến bộ nhớ kém. Và câu trả lời cho foo.attr; // 100% safe access?, là không. Hãy xem xét ví dụ sau:

int &something() { 
    int i = 5, &j = i; 
    return j; // Return reference to local variable. This is destroyed at end of scope. 
} 

int main() { 
    int &k = something(); // Equivalent to getFoo() 
    std::cout << k << endl; // Using this reference is undefined behavior. 
    return 0; 
} 

Live example.

Các tài liệu tham khảo k không được trỏ đến bộ nhớ chính đáng. Nhưng điều này vẫn sẽ biên dịch. Tuy nhiên, không có trường hợp nào có thể xảy ra, nơi lập trình viên không mắc lỗi. Trong trường hợp này, hàm something() được viết không chính xác và sẽ cần phải được sửa. Không có cách nào, hoặc lý do để kiểm tra điều này. Nếu một hàm trả về một tham chiếu xấu thì điều duy nhất bạn có thể (và nên làm) là sửa chữa hàm vi phạm.

+0

Tôi có phản đối tương tự với câu trả lời này như tôi làm với Bejamin's. Trong khi đúng, đây là trường hợp quan trọng nhất cần lưu ý vì nó chỉ có thể xảy ra nếu có một lỗi trong mã ở đâu đó khác. –

+0

@DavidSchwartz Nhưng tôi đã đề cập đến điều này? Tôi không chắc chắn nếu nó là rõ ràng, nhưng trong câu trả lời cho điều này: 'foo.attr; // 100% truy cập an toàn? Tôi tin rằng tôi đã trả lời đúng. Không ... nếu người lập trình 'getFoo()' đã phạm sai lầm. –

+0

Tôi không có vấn đề gì với những gì bạn đã đề cập. Vấn đề của tôi là với những gì bạn không đề cập đến - mã can thiệp đó có thể làm cho một tham chiếu hợp lệ không còn giá trị. –

23

Tham chiếu phải tham chiếu đến đối tượng hợp lệ khi tham chiếu đó được đặt. Đây là một yêu cầu chuẩn C++ và bất kỳ mã nào vi phạm nó là UB và có thể làm bất cứ điều gì theo nghĩa đen.

Tuy nhiên, nó là hoàn toàn hợp pháp để tiêu diệt đối tượng một tham chiếu đề cập đến sau khi tham chiếu đó là ngồi. Tại thời điểm đó, việc truy cập tài liệu tham khảo là bất hợp pháp. Ví dụ:

std::vector<int> j; 
j.push_back(3); 
int& k = j.front(); // legal, object exists now 
j.clear();   // legal, object may be destroyed while reference exists 
k++;    // illegal, destruction of object invalidates reference 

Điều này có nghĩa là hàm trả về tham chiếu phải luôn trả về tham chiếu hợp lệ khi được trả về. Đây là lý do tại sao gọi front trên một véc tơ trống là UB - một tham chiếu phải hợp lệ khi nó được ngồi.Tuy nhiên, thường sẽ có các điều kiện mà sau đó có thể vô hiệu hóa tham chiếu đó và bạn cần phải hiểu những điều kiện đó là gì nếu bạn định cố gắng chặn đứng tham chiếu và truy cập nó sau này.

Nói chung, bạn nên cho rằng không an toàn để chặn một tham chiếu được trả về và truy cập nó sau này trừ khi bạn biết rằng tham chiếu sẽ vẫn hợp lệ. Ví dụ: std::vector giải thích cẩn thận trong điều kiện nào tham chiếu vào vùng chứa có thể bị vô hiệu và bao gồm lệnh gọi tiếp theo đến push_back. Vì vậy, đây được chia:

std::vector<int> j; 
j.push_back(3); 
int &first = j.front(); 
j.push_back(4); 
int &second = j.back(); 
if (first == second) // illegal, references into container are invalidated by push_back 

Nhưng điều này là tốt:

std::vector<int> j; 
j.push_back(3); 
j.push_back(4); 
int &first = j.front(); 
int &second = j.back(); 
if (first == second) // legal, references into container stay valid 
+4

Lưu ý cho OP, không có cách nào phát hiện 'k' không hợp lệ trước khi thực hiện' k ++ '. Giá trị của 'k' là thứ bạn phải đảm bảo thông qua logic của chương trình trong việc đạt đến điểm đó. –

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