2012-11-22 39 views
7

Tôi có một nghi ngờ về trở về std :: string như tham chiếu const.Quay trở lại std :: chuỗi như tham chiếu const

class sample 
{ 
public: 
    std::string mString; 
    void Set(const std::string& s) 
    { 
    mString = s; 
    } 
    std::string Get() 
    { 
    return mString; 
    } 
}; 

Trong hàm Đặt tôi chuyển chuỗi std :: như tham chiếu const, const vì giá trị của nó không thay đổi bên trong hàm.

Và chức năng Nhận, thực sự tôi bị nhầm lẫn ở đây. Trả về std :: string là giá trị có ý nghĩa hơn. Nhưng tôi không chắc chắn rằng, bằng cách chuyển chuỗi như tham chiếu const làm cho bất kỳ lợi thế. Bằng cách giữ lại chuỗi như tham chiếu sẽ làm tăng tốc độ exectuion, tôi nghĩ như vậy, nhưng tôi không chắc chắn. Nhưng trả lại nó như 'const làm cho bất kỳ lợi ích cho điều này?

Trả lời

10

Trả về tham chiếu hoặc tham chiếu const không có chênh lệch tốc độ - cả hai đều rất nhanh vì chúng chỉ trả lại tham chiếu đến đối tượng gốc, không có sự sao chép nào.

Một đối tượng được trả về bởi tham chiếu (không phải) có thể được sửa đổi thông qua tham chiếu đó. Trong ví dụ cụ thể của bạn, mString là công khai, vì vậy, nó có thể được sửa đổi (và trực tiếp). Tuy nhiên, cách tiếp cận thông thường với getters và setters (và lý do chính để giới thiệu) là đóng gói - bạn chỉ cho phép truy cập vào các thành viên dữ liệu của bạn thông qua getter/setter, để bạn có thể phát hiện các giá trị không hợp lệ. nói chung giữ cho các chi tiết thực hiện của lớp ẩn bên trong nó. Vì vậy, getters thường trở lại bằng tham chiếu const hoặc theo giá trị.

Tuy nhiên, nếu bạn quay trở lại tham chiếu const, nó liên kết bạn với luôn luôn giữ một phiên bản std::string trong lớp học của bạn để sao lưu tham chiếu. Đó là, ngay cả khi sau này bạn muốn thiết kế lại lớp học của bạn để nó tính toán chuỗi trên bay trong getter thay vì lưu trữ nó trong nội bộ, bạn không thể. Bạn sẽ phải thay đổi giao diện công cộng của bạn cùng một lúc, có thể phá vỡ mã bằng cách sử dụng lớp.Ví dụ, miễn là bạn quay trở lại bởi const-tài liệu tham khảo, đây là mã hoàn toàn hợp lệ:

const std::string *result = &aSample.Get(); 

Mã này sẽ đương nhiên tạo ra một con trỏ tòn ten không còn biên dịch nếu Get() được thay đổi để trở lại theo giá trị thay vì tham chiếu const. (nhờ Steve Jessop sửa lỗi cho tôi)

Tóm lại, cách tiếp cận tôi cần thực hiện là thực hiện mString riêng tư. Get() có thể trả về theo giá trị hoặc bằng tham chiếu const, tùy thuộc vào mức độ chắc chắn của bạn mà bạn sẽ luôn có một chuỗi được lưu trữ. Lớp sau đó sẽ trông như thế này:

class sample 
{ 
    std::string mString; 

public: 
    void Set(const std::string &s) 
    { 
    mString = s; 
    } 
    std::string Get() const 
    { 
    return mString; 
    } 
}; 
+1

"Mã này tất nhiên sẽ tạo ra một con trỏ lơ lửng nếu Get() được thay đổi để trả về giá trị thay vì tham chiếu const." - không có nó sẽ không, nó sẽ ngừng biên dịch ("không thể lấy địa chỉ tạm thời"). Mà là tốt hơn so với biên dịch nhưng với UB. Trên thực tế nó * có thể * biên dịch do một phần mở rộng, nhưng tôi không nghĩ rằng đó là một phần mở rộng phổ biến và tiêu chuẩn vẫn gọi cho một chẩn đoán để người sử dụng nên được ít nhất là cảnh báo. –

+0

@SteveJessop Cảm ơn, tôi đã sửa câu trả lời. – Angew

0

Trả lại dưới dạng tham chiếu. Nếu một bản sao là cần thiết, nó chắc chắn có thể được thực hiện từ tham chiếu đó.

+0

Điều gì về trả lại nó là 'const' ?? –

+0

Nếu bạn muốn chuỗi chỉ được sửa đổi bằng phương thức 'Set', hãy định nghĩa' Get' là 'const std :: string & Get() const {return mString; } ' – chill

13

Vấn đề quyết định làm thế nào để trả về một đối tượng không tầm thường từ một số loại của một container là thực sự không tầm thường:

  • Nếu lớp mà từ đó bạn quay trở lại giá trị của mình áp đặt bất kỳ loại hạn chế trên đối tượng, bạn không thể trả về tham chiếu không phải là const vì nó sẽ mất khả năng thực thi các bất biến của nó. Rõ ràng, trả về một đối tượng theo tham chiếu không phải là const chỉ khả thi nếu đối tượng hàm thành viên được gọi cũng không phải là const.
  • Hiển thị tham chiếu const cho đối tượng sẽ tránh được sự cố với các bất biến nhưng vẫn ngụ ý rằng đối tượng thuộc loại tương ứng thực sự được giữ bên trong dưới dạng chi tiết triển khai.
  • Trả về một đối tượng theo giá trị có thể phải chịu chi phí đáng kể để sao chép đối tượng.

Nếu lớp học của bạn là tiếp tục khả thi, hãy chắc chắn muốn trả về đối tượng theo giá trị vì nếu không thì đối tượng có thể bị đột biến trước khi người gọi có bất kỳ cơ hội nào để sao chép đối tượng.

Về cơ bản, không có lựa chọn nào là lý tưởng. Khi nghi ngờ, tôi trở lại bằng giá trị trừ khi đối tượng được biết là tốn kém để sao chép trong trường hợp đó, có thể trả lại bằng const&.

+1

Có. Tôi biết đây là một câu hỏi cũ, nhưng đặc biệt là trong trường hợp của một giao diện, nơi mà một trong những không muốn đặt ra những hạn chế về thực hiện, bằng cách trả về giá trị chủ yếu là tốt hơn. –

+0

Thay vào đó, bạn có cân nhắc trả về unique_ptr không? –

0

Điều phổ biến nhất để làm ở đây sẽ được trả về giá trị như một const tham chiếu, sau đó bạn có thể sử dụng một tham chiếu hoặc sao chép các giá trị khi cần thiết:

const std::string& Get() const 
{ 
    return mString; 
} 

sample mySample; 
const std::string &refString = mySample.Get(); // Const-reference to your mString 
const std::string copyString = mySample.Get(); // Copy of your mString 

Nếu bạn thực sự cần để trả về một bản sao của chuỗi, sau đó bạn có thể tránh sao chép các giá trị chuỗi trở lại bằng cách sử dụng "The Most Important Const":

sample mySample; 
const std::string &myString = mySample.Get(); 
// myString is now valid until it falls out of scope, even though it points to a "temporary" variable 
Các vấn đề liên quan