2009-07-15 29 views
56

Khi tôi biên dịch mã C++ với GCC 4.3 lần đầu tiên, (sau khi biên dịch thành công mà không có cảnh báo trên 4.1, 4.0, 3.4 với tùy chọn -Wall -Wextra) một loạt các lỗi của biểu mẫu warning: type qualifiers ignored on function return type.Cảnh báo gcc phụ: loại vòng loại trên hàm trả về

Cân nhắc temp.cpp:

class Something 
{ 
public: 
    const int getConstThing() const { 
     return _cMyInt; 
    } 
    const int getNonconstThing() const { 
     return _myInt; 
    } 

    const int& getConstReference() const { 
     return _myInt; 
    } 
    int& getNonconstReference() { 
     return _myInt; 
    } 

    void setInt(const int newValue) { 
     _myInt = newValue; 
    } 

    Something() : _cMyInt(3) { 
     _myInt = 2; 
    } 
private: 
    const int _cMyInt; 
    int _myInt; 
}; 

Chạy g++ temp.cpp -Wextra -c -o blah.o:

temp.cpp:4: warning: type qualifiers ignored on function return type 
temp.cpp:7: warning: type qualifiers ignored on function return type 

Ai đó có thể cho tôi biết những gì tôi đang làm sai mà vi phạm các tiêu chuẩn C++? Tôi cho rằng khi trở về theo giá trị, số const hàng đầu là thừa, nhưng tôi không hiểu tại sao cần phải tạo cảnh báo với nó. Có những nơi khác mà tôi nên rời khỏi const?

+0

Xem câu hỏi và câu trả lời tương tự này: http://stackoverflow.com/questions/1607188/why-is-type-qualifier-on-return-type-is-meaningless –

+7

Tôi đã thấy cảnh báo như thế này trước đây, tuy nhiên , Tôi đã dành vài phút cố gắng để hiểu những gì đang xảy ra trong mã của tôi. Có lẽ một báo cáo lỗi tốt hơn sẽ tăng tốc mọi thứ. Thay vì 'cảnh báo: loại vòng loại bỏ qua trên hàm trả về loại' giống như' cảnh báo: vui lòng không thêm vòng loại const khi bạn trở lại theo giá trị'. – Avio

Trả lời

77

Nó không vi phạm tiêu chuẩn. Đó là lý do tại sao họ cảnh báo và không phải lỗi.

Và thực sự bạn đã đúng - số const hàng đầu là không cần thiết. Trình biên dịch cảnh báo bạn bởi vì bạn đã thêm mã trong các trường hợp khác có thể có nghĩa là gì đó, nhưng trong hoàn cảnh này có nghĩa là không có gì, và nó muốn đảm bảo bạn sẽ không thất vọng sau khi các giá trị trả lại của bạn có thể sửa đổi được sau tất cả.

+13

Điều đó cảnh báo và không phải lỗi không có nghĩa gì cả.Mã không hợp lệ khác như 'sizeof (void)' cũng chỉ cảnh báo, nhưng rõ ràng bị cấm. Tiêu chuẩn không biết sự khác biệt giữa cảnh báo và lỗi: Cả hai đều là chẩn đoán. –

+1

@ litb: Những gì anh ấy nói vẫn chính xác. Tất nhiên thực tế là họ cảnh báo không * đảm bảo * rằng nó sẽ không vi phạm tiêu chuẩn như bạn nói, nhưng lý do * họ đang thực hiện cảnh báo thay vì lỗi là những người triển khai trình biên dịch không muốn cấm nó. Và lý do họ không muốn cấm nó là vì nó không vi phạm tiêu chuẩn. – jalf

+1

Liệu nó có vi phạm tiêu chuẩn không? – Philipp

17

Tôi đã gặp cảnh báo này khi biên dịch một số mã sử dụng Boost.ProgramOptions. Tôi sử dụng -Werror để cảnh báo đã giết chết bản dựng của tôi, nhưng vì nguồn gốc của cảnh báo ở độ sâu của Boost tôi không thể loại bỏ nó bằng cách sửa đổi mã của tôi.

Sau nhiều đào tôi thấy tùy chọn trình biên dịch mà vô hiệu hóa các cảnh báo:

-Wno-ignored-qualifiers 

Hope this helps.

+4

Tôi đã có cùng một vấn đề, và kết thúc thiết lập đường dẫn bao gồm của Boost với '-isystem' thay vì' -I', mà ngăn chặn tất cả các cảnh báo được nâng lên bởi tiêu đề Boost. – Philipp

+0

@ Giải pháp của Philipp là giải pháp đúng. Việc sử dụng các ký hiệu -Wno-ignore-qualifiers sẽ ảnh hưởng đến mã của bạn và ngăn trình biên dịch của bạn phát hành các cảnh báo bạn đã tạo, trong khi giải pháp của Philipp sẽ không ảnh hưởng đến các cảnh báo được tạo bởi mã của riêng bạn. – Wond3rBoi

-5

Scott Meyers chỉ ra rằng có lý do khá tốt lý do ai đó muốn trả lại giá trị const. Dưới đây là ví dụ:

int some_calculation(int a, int b) { int res = 0; /* ... */ return res; } 

/* Test if the result of the calculation equals 40.*/ 
if (some_calculation(3,20) = 40) 
{ 

} 

Bạn có thấy những gì tôi đã làm sai không? Mã này là hoàn toàn chính xác và nên biên dịch. Vấn đề là trình biên dịch không hiểu rằng bạn dự định để so sánh thay vì gán giá trị 40.

Với giá trị trả về const ví dụ trên sẽ không biên dịch. Vâng, ít nhất là nếu trình biên dịch không loại bỏ từ khóa const.

+14

Không, nó không nên biên dịch. Kết quả của 'some_calculation' là một rvalue của kiểu int. Bạn không thể gán giá trị cho loại không thuộc loại. –

+1

Và nếu giá trị trả về thuộc loại lớp, 'const' là chính xác và không tạo ra cảnh báo. – Philipp

+0

Bạn đã thực sự cố gắng biên dịch ví dụ này chưa? GCC cho "lỗi: lvalue yêu cầu như toán hạng trái của phân công", clang ++ cho "lỗi: biểu thức không thể gán" – Bulletmagnet

2

Có này

struct Foo { Foo(int) {} operator bool() { return true; } };

Foo some_calculation(int a, int b) { Foo result(a + b); /*...*/ return result; }

ví dụ

if (some_calculation(3, 20) = 40) { /*...*/ }

biên dịch mà không có một cảnh báo. Tất nhiên, điều này là hiếm. Nhưng không phải là const đúng đắn về việc làm cho nó khó khăn cho mọi người làm những việc sai? Và với kỳ vọng rằng mọi người thử mọi thứ, điều đó sai, kiểu trả về phải được khai báo const. Và: g ++ cảnh báo về việc bỏ qua trình phân loại, nhưng không bỏ qua nó. Tôi nghĩ, cảnh báo là về người dùng lấy bản sao và bỏ qua các bộ phân loại const trên bản sao của họ. Nhưng đó không phải là một cảnh báo, bởi vì đây là hành vi hoàn toàn chính xác. Và nó có ý nghĩa để làm điều này.

+3

G ++ sẽ không cảnh báo ở đây nếu bạn thêm 'const'. Bộ định tính 'const' chỉ bị bỏ qua đối với các giá trị trả về kiểu không thuộc lớp. – Philipp

1

Không nên sử dụng sai ngữ cảnh cho phép tuân thủ nghiêm ngặt tiêu chuẩn ISO? Tùy thuộc vào = -std tất nhiên ...

1

Cảnh báo này cũng rất hữu ích để tránh nhầm lẫn khi tuyên bố chức năng trở về con trỏ đến đối tượng mà không nên được sửa đổi:

// "warning: type qualifiers ignored on function return type" 
// as the pointer is copied. 
Foo* const bar(); 

// correct: 
const Foo* bar(); 
4

Trả về một giá trị không đổi chỉ có ý nghĩa khi bạn trả về một tham chiếu hoặc một con trỏ (trong trường hợp này con trỏ đến hằng số và không phải là một con trỏ liên tục) bởi vì người gọi có thể sửa đổi giá trị tham chiếu (được trỏ tới).

Một bình luận trên các mã không liên quan đến câu hỏi của bạn: Tôi nghĩ rằng nó tốt hơn để sử dụng một setter thay vì

int& getNonconstReference() { 
    return _myInt; 
} 

nào nên sẽ là:

void setMyInt(int n) { 
    _myInt = n; 
} 

Hơn nữa, nó vô dụng để trả về tham chiếu const cho một int. Nó có ý nghĩa đối với một đối tượng lớn hơn có bản sao hoặc di chuyển đắt hơn.

0

Có sự khác biệt giữa const về kết quả loại cơ bản, trong đó nó bị bỏ qua và const trên kết quả loại lớp, nơi nó thường tàn phá.

namespace i { 
    auto f() -> int const { return 42; } 
    void g(int&&) {} 
} 

namespace s { 
    struct S {}; 
    auto f() -> S const { return {}; } 
    auto g(S&& ) {} 
} 

auto main() -> int 
{ 
    { using namespace i; g(f()); } // OK 
    { using namespace s; g(f()); } // !The `const` prevents this. 
} 

Đây là lý do tại sao trình biên dịch cảnh báo trong trường hợp đầu tiên: đó là trường hợp đặc biệt, có thể không làm được điều mà một người có thể mong đợi.

Để lập trình hiện đại, IMHO cũng sẽ tốt đẹp với cảnh báo về const về kết quả loại lớp vì nó cấm di chuyển ngữ nghĩa; một chi phí khá nghiêm trọng cho bất kỳ lợi thế nhỏ nào được hình dung.

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