2011-08-08 18 views
7

Mã sau đây biên dịch tốt cả với GCC (4.2-4.6) và với Clang (2.1), nhưng khi tôi chạy tệp thực thi nó mang lại cho tôi "Lỗi bus: 10". Tôi không hiểu lý do.const_cast của một thành viên const tĩnh

#include <iostream> 

struct A 
{ 
    static int const v; 
    A() { ++*const_cast<int *>(&A::v); } 
}; 

int const A::v = 0; 

int main(int argc, char * argv[]) 
{ 
    A a, b, c; 
    std::cout << a.v << std::endl; 

    return 0; 
} 
+3

Tôi khá chắc chắn rằng việc sửa đổi một cái gì đó mà bạn khai báo const là hành vi không xác định, nhưng tôi chắc rằng ai đó có thể khai thác câu lệnh chính xác. –

+3

+1 để cung cấp chương trình mẫu hoàn chỉnh tối thiểu. Để biết thêm thông tin, xem http://sscce.org/. –

Trả lời

12

Tôi nghĩ rằng quote liên quan là:

§ 7.1.6.1 (4) from N3242:

Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

Các ví dụ minh họa cho điểm sử dụng const_cast. Như James đã chỉ ra: báo giá có thể được tìm thấy trong §7.1.5 trong tiêu chuẩn C++ 03.

Một chút công phu: Quy tắc ngôn ngữ đó cho phép trình biên dịch sử dụng bộ nhớ chỉ đọc (nếu nó có sẵn trên kiến ​​trúc đích) khi có điều gì đó được khai báo const. Nếu không có quy tắc này, const -ness luôn có thể bị bỏ đi mà không sợ bất kỳ hậu quả nào và việc sử dụng nó sẽ chỉ là vấn đề kỷ luật của nhà phát triển. Cách bạn có thể ít nhất là nói với mọi người rằng họ đang gọi UB, mà thường là một ngăn chặn tốt. Bản thân số const_cast có liên quan nhỏ vì nó không quan trọng cách bạn lừa trình biên dịch trong việc cho phép bạn thao tác một đối tượng const.

4

Vì bạn không được phép sửa đổi các biến được khai báo là const.

2

Tôi không có giải pháp cho vấn đề thực tế. Tôi chỉ có thể nói, không sử dụng const_cast trừ khi ý định là gọi hàm thành viên const từ một hàm không phải thành viên const và "const_cast" kết quả const (để làm cho nó thành một kết quả có thể thay đổi cho hàm không phải thành viên).

Nhưng tôi có một đề nghị để cải thiện thiết kế của bạn:

class A 
{ 
private: 
    static int v; 
public: 
    A() { ++v; } 
    static int get_v() { return v; } 
}; 

int A::v = 0; 

int main(int argc, char * argv[]) 
{ 
    A a, b, c; 
    std::cout << a.get_v() << std::endl; 

    return 0; 
} 
1

Vấn đề là dòng này:

static int const v; 

Bởi vì bạn tuyên bố nó const, các const_cast đang gây ra một hành vi không xác định - ở của bạn trường hợp bạn may mắn khi gặp lỗi bus (đó là lỗi phân đoạn trên hệ thống của tôi).

Tuyên bố không phải là const và bạn có thể gọi const_cast trên đó mà không gặp sự cố.

2

Chỉ vì bạn đã bỏ đi const, không có nghĩa là bạn sẽ thành công bằng văn bản cho bộ nhớ đó.

Tất cả những gì const_cast<T> làm là loại bỏ const-ness của biến khỏi góc nhìn của trình biên dịch. Điều đó cho phép trình biên dịch đi trước và phát ra mã để ghi vào biến. Nhưng trong thời gian chạy, nếu trình biên dịch/liên kết xảy ra để đặt biến trong bộ nhớ chỉ đọc, thì phần cứng sẽ dừng bạn viết ở đó bất kể bạn đúc nó như thế nào.

6

5.2.11.7:

Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier) may produce undefined behavior (7.1.5.1)

Trong trường hợp của bạn, bạn đang cố gắng sửa đổi dữ liệu đó là trong read-only phân khúc.

+1

Đây là ghi chú không quy định (nghĩa là nó chỉ mang tính thông tin). Văn bản quy phạm tại tham chiếu §7.1.5.1. –

+0

Nó là §7.1.6.1 trong bản nháp. Xem câu trả lời của tôi. – pmr

+1

@pmr: Phải, vì đặc tả C++ 0x thêm một mệnh đề định nghĩa 'constexpr'. –

2

Về cơ bản, nếu biến được khai báo là const, trình biên dịch được phép phát ra kết quả để chỉ đọc bộ nhớ. Lấy một con trỏ/tham chiếu đến một đối tượng const và sau đó sử dụng const_cast để xóa const có thể dẫn đến hành vi không xác định.

Nói chung, chỉ an toàn khi sử dụng const_cast nếu đối tượng được tham chiếu là không const (ngay cả khi con trỏ/tham chiếu bạn có là const).