Bán cho tôi về sự đúng đắn


133

Vậy tại sao chính xác là nó luôn được khuyến nghị sử dụng const thường xuyên nhất có thể? Dường như với tôi rằng việc sử dụng const có thể gây đau đớn nhiều hơn là giúp đỡ trong C ++. Nhưng một lần nữa, tôi đến với điều này từ quan điểm của con trăn: nếu bạn không muốn thay đổi điều gì đó, đừng thay đổi nó. Vì vậy, với những gì đã nói, đây là một vài câu hỏi:

  1. Có vẻ như mỗi lần tôi đánh dấu một cái gì đó là const, tôi cũng gặp lỗi và phải thay đổi một số chức năng khác ở đâu đó. Sau đó, điều này khiến tôi phải thay đổi một chức năng khác ở một nơi khác. Đây có phải là một cái gì đó chỉ dễ dàng hơn với kinh nghiệm?

  2. Là những lợi ích của việc sử dụng const thực sự đủ để bù đắp cho những rắc rối? Nếu bạn không có ý định thay đổi một đối tượng, tại sao không viết mã mà không thay đổi nó?

Tôi nên lưu ý rằng tại thời điểm này, tôi tập trung nhiều nhất vào lợi ích của việc sử dụng const cho mục đích chính xác và bảo trì, mặc dù cũng rất hay khi có ý tưởng về ý nghĩa hiệu suất.


1
Hồi tưởng cũ 8yr, nhưng .. Làm thế nào về việc tăng tốc mã của bạn 100x (xem trực tiếp)?
lorro

1
Kiểm tra câu trả lời của tôi ở đây (câu hỏi liên quan, tôi sẽ nói câu trả lời tương tự): stackoverflow.com/questions/42 310477/ Đổi BTW: Tôi yêuconst
Gines Hidalgo

Câu trả lời:


158

Đây là bài viết dứt khoát về "tính đúng đắn": https://isocpp.org/wiki/faq/const-c chính xác .

Tóm lại, sử dụng const là cách thực hành tốt vì ...

  1. Nó bảo vệ bạn khỏi những thay đổi vô tình mà không có ý định thay đổi,
  2. Nó bảo vệ bạn khỏi việc thực hiện các bài tập biến ngẫu nhiên, và
  3. Trình biên dịch có thể tối ưu hóa nó. Chẳng hạn, bạn được bảo vệ khỏi

    if( x = y ) // whoops, meant if( x == y )

Đồng thời, trình biên dịch có thể tạo mã hiệu quả hơn vì nó biết chính xác trạng thái của biến / hàm sẽ luôn luôn như thế nào. Nếu bạn đang viết mã C ++ chặt chẽ, điều này là tốt.

Bạn đúng ở chỗ có thể khó sử dụng hằng số chính xác, nhưng mã kết thúc ngắn gọn và an toàn hơn để lập trình. Khi bạn thực hiện nhiều phát triển C ++, lợi ích của việc này nhanh chóng được thể hiện.


Tôi luôn cho rằng các giá trị const có thể được lưu trữ tự do và do đó tránh được nhiều vấn đề tương tranh hoặc cải thiện tốc độ. Điều đó có đúng không?
Phil H

3
Chắc chắn rồi. constcác biến có thể cải thiện tốc độ theo nghĩa là trình biên dịch có thể tạo mã tối ưu hơn vì nó biết toàn bộ mục đích và việc sử dụng biến. Bạn sẽ nhận thấy sự khác biệt? Vâng, đó là tranh cãi về ứng dụng của bạn. Theo như đồng thời, các biến const là chỉ đọc, điều đó có nghĩa là không cần khóa độc quyền trên các biến đó vì giá trị sẽ luôn giống nhau.
Jordan Parmer

4
Kể từ C ++ 11, thư viện tiêu chuẩn cũng giả sử constcó nghĩa là an toàn luồng và xử lý mã của riêng bạn theo cách này giúp kiểm tra các vấn đề đa luồng có thể dễ dàng hơn và là cách dễ dàng để cung cấp bảo đảm API cho người dùng API của bạn.
pmr

3
Đối với tôi, một trong những giá trị gia tăng lớn nhất của tính chính xác là bạn biết chỉ bằng cách xem các nguyên mẫu hàm khi con trỏ đang tham chiếu dữ liệu không bao giờ bị đột biến bởi hàm (chỉ là đầu vào).
cp.engr

1
Đừng quên rằng có sự hợp lývật lý . Bất kỳ đối tượng tổng hợp nào được đánh dấu là có thể thay đổi đều có thể thay đổi, mặc dù việc đánh dấu nó là như vậy ngụ ý rằng nó không liên quan gì đến hằng số logic của đối tượng chứa.
Adrian

128

Đây là một đoạn mã với một lỗi phổ biến mà tính chính xác có thể bảo vệ bạn chống lại:

void foo(const int DEFCON)
{
   if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
   {
       fire_missiles();
   }
}

19
Vì vậy, chúng tôi nói rằng const là cần thiết bởi vì một số kẻ ngốc đẫm máu đã chọn "=" làm toán tử gán trong C? ;-)
Steve Jessop

37
Tất nhiên, hầu hết các trình biên dịch hiện đại đều cảnh báo về các bài tập trong các điều kiện và tất cả chúng ta đều bật các cảnh báo coi là cờ lỗi, phải: ->
Jack Bould

7
Đừng quá khó với ví dụ đó: Đây là ví dụ tương tự được truyền bá bởi một số nhà phát triển để thuyết phục chúng tôi sử dụng if (0 == i) thay vì if (i == 0). Cuối cùng, mẫu mã của Doug có thể được sử dụng bên ngoài câu lệnh "if". Điều quan trọng là nó cho thấy một trong những lợi ích của const một cách hài hước. + 1.
paercebal

2
Một số trình biên dịch (và gợi ý) đã cảnh báo về điều này trong một thời gian dài và việc bắt lỗi đánh máy này sẽ hữu ích hơn nhiều so với const: codepad.org/Nnf5JUXV .

7
@Roger bạn cho rằng chúng ta đang sống trong một thế giới nơi các bản dựng sạch sẽ và không có cảnh báo. Kinh nghiệm của tôi là trong rất nhiều cảnh báo mã bị mất trong tiếng ồn. Ngoài ra, có rất nhiều mã thực hiện các phép gán trong biểu thức if và nhiều người sẽ cho rằng đó là một kiểu hợp lệ, "tốt".
Doug T.

62

Có vẻ như mỗi lần tôi đánh dấu một cái gì đó là const, tôi cũng gặp lỗi và phải thay đổi một số chức năng khác ở đâu đó. Sau đó, điều này khiến tôi phải thay đổi một chức năng khác ở một nơi khác. Đây có phải là một cái gì đó chỉ dễ dàng hơn với kinh nghiệm?

Từ kinh nghiệm, đây là một huyền thoại hoàn toàn. Nó xảy ra khi không đúng const ngồi với mã const-true, chắc chắn. Nếu bạn thiết kế const-true ngay từ đầu, điều này KHÔNG BAO GIỜ là một vấn đề. Nếu bạn thực hiện một cái gì đó const, và sau đó cái gì khác không hãy biên dịch, trình biên dịch là nói cho bạn một cái gì đó vô cùng quan trọng, và bạn nên dành thời gian để sửa chữa nó đúng cách .


7
Điều này đã giúp tôi ngăn chặn rất nhiều lỗi trong đó tôi có một hàm const sắp gọi một hàm không phải là const vì tôi quên nó sửa đổi dữ liệu bên dưới.
Vịt Mooing

9
Rất ít người luôn bắt đầu với các cơ sở mã sạch. Hầu hết mã hóa là bảo trì mã kế thừa, trong đó nhận xét được trích dẫn là khá chính xác. Tôi sử dụng const khi viết các hàm lá mới, nhưng tôi đặt câu hỏi liệu có đáng để theo đuổi mọi thứ thông qua nửa tá hoặc một chục cấp gọi của mã không quen thuộc.
Warren Dew

3
Điều này là hoàn toàn sai trong kinh nghiệm của tôi. Các loại điểm lồng nhau tạo ra sự đau đầu lớn nhất cho loại điều này, trong đó bạn có thể có nhiều bộ định lượng const trong một loại.
Noldorin

4
"Nếu bạn thiết kế const-true ngay từ đầu", bạn thực sự có bao nhiêu lần buộc phải sửa lỗi const từ chính xác ?? Hầu hết chúng ta phải đối phó với nhiều API và thư viện trên cơ sở hàng ngày, nơi đây không phải là trường hợp và bạn có thể làm rất ít về những điều đó. Vì vậy, tôi đồng ý với tình cảm của OP "Có vẻ như mỗi lần tôi đánh dấu điều gì đó là tôi sẽ gặp lỗi" ...
nyholku

@WarrenDew Đó là một đối số bắc cầu; nếu các tác giả ban đầu đã sử dụng constđúng cách (tức là "từ đầu") thì thực sự sẽ không có vấn đề gì, đó chính xác là vấn đề!
Các cuộc đua nhẹ nhàng trong quỹ đạo

31

Nó không dành cho bạn khi bạn đang viết mã ban đầu. Nó dành cho người khác (hoặc bạn vài tháng sau), người đang xem khai báo phương thức bên trong lớp hoặc giao diện để xem nó làm gì. Không sửa đổi một đối tượng là một phần thông tin quan trọng để lượm lặt từ đó.


1
Đây chỉ là loại đúng. Const được sử dụng như là sự bảo vệ cũng như để thực thi các biến trong thông qua các giao diện và vv.
Jordan Parmer

Đó là, nhưng bạn có thể thực thi điều đó thông qua các thực hành mã hóa có kỷ luật và các trạng thái áp phích. Lợi ích thực sự đến từ việc này được phản ánh trong API.
Antonio Haley

2
Chính xác. Tốt hơn là có "const int Value = 5;" hơn có "int ConstValue = 5;". +1.
paercebal

6
Thời điểm thích hợp để đặt tính chính xác là khi bạn viết API ban đầu. Nếu không, bạn sẽ gặp rắc rối với nhiễm độc const khi bạn trang bị thêm (đó là lý do tại sao việc thêm nó vào mã cũ là một vấn đề hoàn toàn khác với việc thực hiện nó trong mã mới).
Donal Fellows

@DonalFellows điều này không nói đặt vào const sau. Người ta nói rằng bạn sẽ nhận được những lợi ích sau này, khi bạn đọc mã với const đã có mặt
Caleth

27

Nếu bạn sử dụng const một cách chặt chẽ, bạn sẽ ngạc nhiên về số lượng biến thực có trong hầu hết các hàm. Thường không nhiều hơn một bộ đếm vòng lặp. Nếu mã của bạn đạt đến điểm đó, bạn sẽ có cảm giác ấm áp bên trong ... xác thực bằng cách biên dịch ... lĩnh vực lập trình chức năng đang ở gần ... bạn gần như có thể chạm vào nó ngay bây giờ ...


1
kể từ C ++ 17 và sự tốt đẹp của constexpr, tôi đang viết các bài kiểm tra đơn vị thời gian biên dịch ... ngày càng gần hơn ...
QBziZ

22

const là một lời hứa mà bạn đang thực hiện với tư cách là nhà phát triển và tranh thủ sự giúp đỡ của nhà soạn nhạc trong việc thực thi.

Lý do của tôi là const-chính xác:

  • Nó thông báo cho khách hàng về chức năng của bạn rằng bạn sẽ không thay đổi biến hoặc đối tượng
  • Chấp nhận đối số bằng tham chiếu const cung cấp cho bạn hiệu quả của việc chuyển bằng tham chiếu với sự an toàn của việc truyền theo giá trị.
  • Viết giao diện của bạn là const chính xác sẽ cho phép khách hàng sử dụng chúng. Nếu bạn viết giao diện của mình để nhận các tài liệu tham khảo không phải là const, các khách hàng đang sử dụng const sẽ cần bỏ constness để làm việc với bạn. Điều này đặc biệt khó chịu nếu giao diện của bạn chấp nhận không phải là char * và khách hàng của bạn đang sử dụng chuỗi std ::, vì bạn chỉ có thể nhận được một char char * từ họ.
  • Sử dụng const sẽ tranh thủ trình biên dịch để giữ cho bạn trung thực để bạn không thay đổi nhầm thứ gì đó không nên thay đổi.

20

Triết lý của tôi là nếu bạn sẽ sử dụng ngôn ngữ kén chọn với việc kiểm tra thời gian biên dịch hơn là sử dụng tốt nhất ngôn ngữ đó bạn có thể. constlà một trình biên dịch được thực thi theo cách truyền đạt ý nghĩa của bạn ... nó tốt hơn bình luận hoặc doxygen sẽ có. Bạn đang trả giá, tại sao không lấy được giá trị?


20

Lập trình C ++ không có const giống như lái xe không có đai an toàn trên.

Thật đau đớn khi đeo dây an toàn mỗi khi bạn bước lên xe và 364 trong số 365 ngày bạn sẽ đến nơi an toàn.

Sự khác biệt duy nhất là khi bạn gặp rắc rối với chiếc xe của mình, bạn sẽ cảm thấy nó ngay lập tức, trong khi với lập trình mà không có const, bạn có thể phải tìm kiếm trong hai tuần, điều đó gây ra sự cố đó chỉ để phát hiện ra rằng bạn vô tình làm hỏng một đối số chức năng bạn thông qua tham chiếu không const cho hiệu quả.


17

Đối với lập trình nhúng, sử dụng constthận trọng khi khai báo cấu trúc dữ liệu toàn cầu có thể tiết kiệm rất nhiều RAM bằng cách khiến dữ liệu không đổi được đặt trong ROM hoặc flash mà không sao chép vào RAM khi khởi động.

Trong lập trình hàng ngày, sử dụng constcẩn thận sẽ giúp bạn tránh việc viết các chương trình bị sập hoặc hành xử không thể đoán trước vì chúng cố gắng sửa đổi chuỗi ký tự và dữ liệu toàn cầu liên tục khác.

Khi làm việc với các lập trình viên khác trong các dự án lớn, sử dụng constđúng cách sẽ giúp ngăn các lập trình viên khác điều tiết bạn.


13

constgiúp bạn cách ly mã "thay đổi mọi thứ" sau lưng. Vì vậy, trong một lớp, bạn sẽ đánh dấu tất cả các phương thức không thay đổi trạng thái của đối tượng là const. Điều này có nghĩa là các constthể hiện của lớp đó sẽ không thể gọi bất kỳ constphương thức nào nữa. Bằng cách này, bạn đã ngăn chặn việc vô tình gọi chức năng có thể thay đổi đối tượng của bạn.

Ngoài ra, constlà một phần của cơ chế quá tải, vì vậy bạn có thể có hai phương thức có chữ ký giống hệt nhau, nhưng một có constvà không có. Một cái constđược gọi để consttham khảo, và cái còn lại được gọi là không consttham chiếu.

Thí dụ:

#include <iostream>

class HelloWorld {
    bool hw_called;

public:
    HelloWorld() : hw_called(false) {}

    void hw() const {
        std::cout << "Hello, world! (const)\n";
        // hw_called = true;  <-- not allowed
    }

    void hw() {
        std::cout << "Hello, world! (non-const)\n";
        hw_called = true;
    }
};

int
main()
{
    HelloWorld hw;
    HelloWorld* phw1(&hw);
    HelloWorld const* phw2(&hw);

    hw.hw();    // calls non-const version
    phw1->hw(); // calls non-const version
    phw2->hw(); // calls const version
    return 0;
}

13

const đúng là một trong những điều thực sự cần phải được đặt ra ngay từ đầu. Như bạn đã tìm thấy, việc thêm nó vào sau này là một nỗi đau lớn, đặc biệt là khi có rất nhiều sự phụ thuộc giữa các chức năng mới mà bạn đang thêm và các chức năng không chính xác cũ đã tồn tại.

Trong rất nhiều mã mà tôi viết, nó thực sự đáng nỗ lực vì chúng ta có xu hướng sử dụng bố cục rất nhiều:

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };

Nếu chúng tôi không có tính chính xác, thì bạn sẽ phải dùng đến việc trả lại các vật thể phức tạp theo giá trị để đảm bảo với bản thân rằng không ai thao túng trạng thái bên trong của lớp B sau lưng bạn.

Nói tóm lại, const-đúng là một cơ chế lập trình phòng thủ để cứu bản thân khỏi nỗi đau trên đường.


7

Giả sử bạn có một biến trong Python. Bạn biết bạn không cần phải sửa đổi nó. Nếu bạn vô tình làm gì?

C ++ cung cấp cho bạn một cách để bảo vệ bản thân khỏi việc vô tình làm điều gì đó mà bạn không thể làm được ngay từ đầu. Về mặt kỹ thuật, bạn có thể đi xung quanh nó bằng mọi cách, nhưng bạn phải làm thêm để tự bắn.


4

Có một bài viết hay ở đây về const trong c ++. Đó là một ý kiến ​​khá thẳng về phía trước nhưng hy vọng nó sẽ giúp một số.


3

Khi bạn sử dụng từ khóa "const", bạn chỉ định giao diện khác cho các lớp của mình. Có một giao diện bao gồm tất cả các phương thức và một giao diện chỉ bao gồm các phương thức const. Rõ ràng điều này cho phép bạn hạn chế quyền truy cập vào một số điều mà bạn không muốn thay đổi.

Vâng, nó trở nên dễ dàng hơn với thời gian.


2

Tôi thích sự đúng đắn ... về lý thuyết. Bởi mỗi lần tôi cố gắng áp dụng nó một cách nghiêm túc trong thực tế, cuối cùng nó đã bị hỏng và const_cast bắt đầu leo ​​lên trong việc làm cho mã trở nên xấu xí.

Có thể nó chỉ là các mẫu thiết kế tôi sử dụng, nhưng const luôn luôn là một bàn chải quá rộng.

Ví dụ, hãy tưởng tượng một công cụ cơ sở dữ liệu đơn giản ... nó có các đối tượng lược đồ, bảng, trường, v.v. Người dùng có thể có con trỏ 'const Table' nghĩa là họ không được phép sửa đổi lược đồ bảng ... nhưng về thao tác dữ liệu liên quan đến bảng? Nếu phương thức Chèn () được đánh dấu const thì bên trong nó phải bỏ hằng số để thực sự thao tác cơ sở dữ liệu. Nếu nó không được đánh dấu const thì nó không bảo vệ khỏi việc gọi phương thức AddField.

Có thể câu trả lời là phân chia lớp học dựa trên các yêu cầu không thể thiếu, nhưng điều đó có xu hướng làm phức tạp thiết kế hơn tôi mong muốn vì lợi ích mà nó mang lại.


Tôi nghĩ rằng ví dụ của bạn là một trường hợp lạm dụng const, nhưng đừng quên công cụ sửa đổi có thể thay đổi, có thể được áp dụng cho các biến thể hiện để loại bỏ hằng số.
Zooba

2
Khi nào một hàm Chèn () sẽ được đánh dấu const trừ khi nó được đặt tên sai? Thêm những thứ thường sửa đổi những thứ bạn đã thêm nó, có nghĩa là nó không phải là const. Những gì bạn thực sự muốn là một TableWithConstSchema.
Greg Rogers

Tôi có thể thêm một lớp khác, nhưng tôi không muốn làm cho API phức tạp một cách không cần thiết hoàn toàn vì mục đích chính xác.
Rob Walker

1

Bạn cũng có thể đưa ra gợi ý về trình biên dịch với const .... theo đoạn mã sau

#include <string>

void f(const std::string& s)
{

}
void x( std::string& x)
{
}
void main()
{
    f("blah");
    x("blah");   // won't compile...
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.