Khả năng đọc là một lý do hợp lệ để không sử dụng const trong các tham số (tham chiếu)?


24

Khi viết một số hàm, tôi tìm thấy một từ khóa const trong các tham số như thế này:

void MyClass::myFunction(const MyObject& obj,const string& s1,const string& s2,const string& s3){
}

thường gây ra việc chia một dòng thành 2 dòng trong IDE hoặc vim, vì vậy tôi muốn xóa tất cả các từ khóa const trong tham số:

void MyClass::myFunction(MyObject& obj,string& s1,string& s2,string& s3){
} 

Đó có phải là một lý do hợp lệ để không sử dụng const? Có thể duy trì để giữ các đối tượng tham số không thay đổi bằng tay?


110
"Này, tôi muốn thay đổi chức năng chương trình của mình" để làm cho nó dễ đọc hơn là một lý do tồi tệ.
Pieter B

37
Dù sao, chương trình sẽ không trở nên dễ đọc hơn nữa - Một khi bạn thấy một thứ gì đó được bàn giao vì constbạn có một gợi ý mạnh mẽ rằng bạn không cần bận tâm làm thế nào nó có thể được thay đổi trong chức năng.
tofro

43
Một cách tốt hơn để cải thiện khả năng đọc là giảm số lượng đối số.
5gon12eder

15
'const' có thể cải thiện khả năng đọc. Tuyên bố này làm rõ rằng obj có thể không thay đổi!
Charles

14
Điều gì sẽ giúp dễ đọc là thêm một khoảng trắng sau mỗi dấu phẩy.
sam hocevar

Câu trả lời:


182

Khả năng đọc là một lý do hợp lệ để học cách sử dụng khoảng trắng:

void MyClass::myFunction(
        const MyObject& obj,
        const string& s1,
        const string& s2,
        const string& s3
) {
    return;
}

Nằm ở đằng kia, các tham số sẽ không bị nhầm lẫn với phần thân của hàm. Bằng cách định vị chúng trên một dòng khác, bạn sẽ không phải định vị lại chúng khi bạn đổi tên myFunctionthành một cái gì đó mô tả hơn. Không thay đổi vị trí tham số khi chúng không thay đổi là điều mà người dùng công cụ diff kiểm soát nguồn sẽ đánh giá cao.

constcó một ý nghĩa nào đó. Đừng vứt nó đi chỉ vì bạn hết không gian và ý tưởng. Khả năng đọc là vua nhưng phá vỡ mọi thứ trong tên của nó chỉ là từ bỏ.


6
"bạn sẽ không phải định vị lại chúng khi bạn thay đổi tên của myFactor" - mặc dù trong trường hợp này có vẻ như chúng đã được định vị để sắp xếp gần đúng với lỗ mở (và nếu đó là trường hợp thì bạn có thể phải định vị lại chúng nếu độ dài của tên lớp + tên hàm thay đổi nhiều hơn khoảng 4 ký tự. Vì vậy, nếu bạn muốn không phải làm điều đó, hãy thêm một số mức thụt đầu dòng cố định, không phải là một số phụ thuộc vào độ dài của tên hàm. Tôi muốn giới thiệu 1 cấp độ, câu trả lời này sử dụng 6, nhưng bất kỳ số cố định nào cũng đạt được mục tiêu đã nêu :-)
Steve Jessop

6
@CandiedOrange Tôi ngạc nhiên khi bạn không sử dụng "mẫu 6" trong câu trả lời này ... rõ ràng là nó ít xấu xí hơn!
Svidgen

6
Mẫu 6 cho chiến thắng. Một tabspace cho một cấp độ thụt. Đơn giản và hiệu quả. Vấn đề đã được giải quyết :)
Cuộc đua nhẹ nhàng với Monica

2
Ok ok mẫu 6 nó là. Đây là biến thể mà JeffGrigg đã đề cập trên c2.
candied_orange

4
@ Random832 Tôi nghĩ bây giờ chúng tôi đang ở trong khu vực đổ xe đạp. Đây là cách thích hợp để giải quyết rằng: tìm kiếm cơ sở mã của bạn để biết ví dụ, tham khảo hướng dẫn về phong cách cửa hàng của bạn, hỏi các nhà phát triển trong cửa hàng của bạn và nếu không có cách nào mang lại câu trả lời có thẩm quyền thì hãy sử dụng câu trả lời này. Giải quyết các tranh chấp có thể đi bằng một phần tư. Một khi quý đã nói được nhất quán!
candied_orange

52

Trên thực tế, vấn đề dễ đọc chắc chắn đi theo hướng khác. Đầu tiên, bạn có thể giải quyết một cách tầm thường dòng chạy của mình bằng cách sử dụng khoảng trắng . Nhưng loại bỏ constkhông chỉ làm cho dòng ngắn hơn, nó thay đổi hoàn toàn ý nghĩa của chương trình.

Herb Sutter đề cập đến consttài liệu tham khảo constquan trọng nhấtconst bởi vì một tài liệu tham khảo constcó thể liên kết với tạm thời và kéo dài tuổi thọ của nó. Một tham chiếu giá trị đến không constthể, bạn cần một biến riêng.

void foo_const(std::string const& );
void foo_nc(std::string& );

std::string some_getter();

foo_const(some_getter());      // OK
foo_const("Hello there"); // OK

foo_nc(some_getter()); // error
foo_nc("Nope");   // error

std::string x = some_getter(); // have to do this
foo_nc(x);                     // ok
std::string msg = "Really??";  // and this
foo_nc(msg);                   // ok

Điều này có nghĩa là khả năng sử dụng là bạn sẽ phải giới thiệu tất cả các biến tạm thời này chỉ để có thể gọi hàm của bạn. Điều đó không tốt cho khả năng đọc, vì các biến này là vô nghĩa và chỉ tồn tại vì chữ ký của bạn sai.


6
Đoạn thứ hai của bạn khiến tôi đau đầu khi cố gắng tìm hiểu xem liệu constđang đề cập đến điều này consthay điều khác constvà điều gì constthực sự quan trọng nhấtconst
Mindwin

3
@Mindwin Tôi nghĩ điều trớ trêu là đoạn thứ hai của tôi rõ ràng và không mơ hồ, và tôi không biết bạn đang nói về cái gì.
Barry

2
@Barry Nó chắc chắn không rõ ràng, nhưng tôi phải mất vài lần đọc đoạn đó để cố gắng hiểu ý nghĩa của nó. Tôi nghĩ một số rắc rối là nó có thể được phân tích cú pháp "Herb Sutter đề cập đến const (liên quan đến const) là const quan trọng nhất ..." hoặc "Herb Sutter đề cập đến const trong (tham chiếu đến const) là nhất const const ... "Tôi tin rằng cái sau là nhóm từ hợp lệ duy nhất, nhưng phải mất một chút để xử lý nó. Có lẽ có một cách để sử dụng dấu ngoặc kép để loại bỏ sự mơ hồ?
Cort Ammon - Phục hồi lại

1
Tôi nghĩ rằng một số hợp chất gạch nối sẽ làm rõ điều này.
Shawnt00

2
hoặc đặc biệt sử dụng const&thay vì tham chiếu đến constnhư một danh từ (cụm từ) ở đó
Caleth

21

Câu trả lời đơn giản là "không".

Câu trả lời dài là consttừ khóa là một phần của hợp đồng mà hàm cung cấp; nó cho bạn biết rằng đối số sẽ không được sửa đổi. Khoảnh khắc bạn gỡ bỏ constbảo đảm ra khỏi cửa sổ. Hãy nhớ rằng bạn không thể duy trì hợp lý độ chụm (hoặc bất kỳ thuộc tính nào khác) của một thứ gì đó bằng cách sử dụng tài liệu, quy ước hoặc hướng dẫn - nếu hằng số không được thực thi bởi trình biên dịch, ai đó sẽ nghĩ rằng họ có thể làm cho công việc của họ dễ dàng hơn nếu họ sử dụng tham số "chỉ một chút thôi". Xem xét:

// parameter "foo" is not modified
void fna(Foo& foo);

void fnb(const Foo& foo);

Ngoài thực tế là phiên bản sau ngắn gọn hơn, nó cũng cung cấp hợp đồng mạnh hơn và cho phép trình biên dịch giúp bạn duy trì ý định của mình. Cái trước không làm gì để ngăn fna(Foo&)chức năng sửa đổi tham số bạn truyền cho nó.

Như trong câu trả lời @CandiedOrange, bạn có thể sử dụng khoảng trắng để bố trí mã và tăng cường khả năng đọc.


14

Xóa consttừ khóa sẽ loại bỏ khả năng đọcconsttruyền thông tin đến người đọc và trình biên dịch.
Giảm độ dài mã ngang là tốt (không ai thích cuộn sang một bên) nhưng có nhiều thứ consthơn là văn bản. Bạn có thể viết lại nó:

typedef string str;
typedef MyObject MObj;
void MyClass::myFunction(const MObj& o,const str& s1,const str& s2,const str& s3)

Điều này không thay đổi hợp đồng nhưng đáp ứng nhu cầu giảm chiều dài đường dây. Thực sự tôi sẽ coi đoạn trích trên là ít đọc hơn và sẽ chọn sử dụng nhiều khoảng trắng hơn như đã được đề cập trong câu trả lời của CandiedOrange.

constlà một chức năng của chính mã. Bạn sẽ không làm cho hàm không phải là thành viên để xóa MyClass::phần khai báo, vì vậy đừng xóaconst


4
Tôi đồng ý rằng đoạn trích bạn cung cấp ít đọc hơn. Nó buộc một người đọc đi tìm hiểu những gì MObjstrđang có, và chắc chắn làm tăng lông mày. Điều này đặc biệt kỳ lạ đối với các loại có tên mà bạn đã kiểm soát: Ví dụ: Tại sao bạn không đặt tên MyObjectnhư vậy MObjđể bắt đầu?
Jason C

3

Là khả năng đọc là một lý do hợp lệ để không sử dụng const trong các tham số?

Không. Bỏ qua constcó thể thay đổi chức năng, mất các biện pháp bảo vệ constvà có khả năng tạo mã kém hiệu quả hơn.

Có thể duy trì để giữ các đối tượng tham số không thay đổi bằng tay?

Thay vì dành thời gian tự tạo

void MyClass::myFunction(const MyObject& obj,const string& s1,const string& s2,const string& s3){
  //
}

Sử dụng các công cụ định dạng tự động . Viết hàm theo các yêu cầu chức năng của nó và để tự động định dạng xử lý bản trình bày. Điều chỉnh định dạng thủ công không hiệu quả bằng sử dụng định dạng tự động và sử dụng thời gian đã lưu để cải thiện các khía cạnh khác của mã.

void MyClass::myFunction(const MyObject& obj, const string& s1, const string& s2, 
    const string& s3) {
  // 
}

-1

Càng lâu càng tốt để giữ const. Nó cải thiện bảo trì mã rất nhiều (không cần phỏng đoán để xem phương thức này có thay đổi đối số của tôi không).

Nếu tôi thấy nhiều đối số trong một phương thức, nó buộc tôi phải xem xét việc tạo jaron dựa trên dự án (Ma trận, Nhân viên, Hình chữ nhật, Tài khoản) sẽ ngắn hơn nhiều, dễ hiểu hơn (loại bỏ danh sách dài các đối số cho các phương thức).


Đã đồng ý. Tôi đã do dự để chỉ ra nó. Như vậy, "trường hợp cực đoan".
bôi đen

@cmaster Điều đó nói rằng, đôi khi trong một số bối cảnh nhất định, với một số lập trình viên nhất định, nó có thể đọc được. Ví dụ, trong trường hợp rất cụ thể của một chương trình trong các lệnh gọi API Windows, với một trình đọc quen với môi trường đó, ví dụ như typedef Point * LPPOINT, và typedef const Point * LPCPOINTtrong khi siêu đáng ghét, vẫn mang một ý nghĩa ngầm, bởi vì nó phù hợp với mong đợi ngay lập tức trong ngữ cảnh. Nhưng không bao giờ trong trường hợp chung; đó chỉ là một ngoại lệ kỳ lạ mà tôi có thể nghĩ ra.
Jason C

1
Vâng, khi tôi thấy câu hỏi, "const unsign long long int" xuất hiện trong đầu tôi, nhưng, nó không phải là một ứng cử viên tốt để có được lợi ích từ "const" hoặc "tham chiếu". Typedef giải quyết vấn đề chung về rút ngắn tên; nhưng nó không cảm thấy giống như thiết kế tốt để che giấu mục đích của các cấu trúc ngôn ngữ (như "const") đằng sau nó.
bôi đen
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.