Sự khác biệt giữa `const shared_ptr <T>` và `shared_ptr <const T>`?


115

Tôi đang viết một phương thức truy cập cho một con trỏ dùng chung trong C ++ diễn ra như sau:

class Foo {
public:
    return_type getBar() const {
        return m_bar;
    }

private:
    boost::shared_ptr<Bar> m_bar;
}

Vì vậy, để hỗ trợ const-ness của getBar()kiểu trả về phải là một boost::shared_ptrngăn cản việc sửa đổi Barnó trỏ tới. Tôi đoán đó shared_ptr<const Bar>là kiểu mà tôi muốn quay lại để làm điều đó, ngược lại const shared_ptr<Bar>sẽ ngăn việc gán lại chính con trỏ để trỏ đến một điểm khác Barnhưng cho phép sửa đổi điểm Barmà nó trỏ tới ... Tuy nhiên, tôi không chắc. Tôi sẽ đánh giá cao nếu ai đó biết chắc chắn có thể xác nhận điều này hoặc sửa cho tôi nếu tôi sai. Cảm ơn!


3
Đó chính xác là những gì bạn đã nói. Bạn có thể xem tài liệu dành cho các nhà khai thác *->xác nhận điều này.
syam

2
Sự khác biệt giữa T *constvà là T const *gì? Giống nhau.

3
@ H2CO3 Không hề. Các constthường Sửa gì _precedes nó, vì vậy T *constlà một constcon trỏ tới T, và T const*là một con trỏ đến const T. Và tốt nhất là tránh sử dụng constkhông có gì trước nó.
James Kanze,

6
@JamesKanze, đó là điểm H2CO3 của: sự khác biệt giữa T *constT const *cũng giống như sự khác biệt giữa const shared_ptr<T>shared_ptr<const T>
Jonathan Wakely

1
@JamesKanze Ồ nhưng có. T *constlà một con trỏ const tới không phải const T, do đó const shared_ptr<T>. Ngược lại, T const *là một con trỏ không phải const const T, do đó shared_ptr<const T>.

Câu trả lời:


176

Bạn đúng rồi. shared_ptr<const T> p;tương tự với const T * p;(hoặc, tương đương, T const * p;), nghĩa là, đối tượng nhọn consttrong khi const shared_ptr<T> p;tương tự với T* const p;nghĩa pconst. Tóm tắt:

shared_ptr<T> p;             ---> T * p;                                    : nothing is const
const shared_ptr<T> p;       ---> T * const p;                              : p is const
shared_ptr<const T> p;       ---> const T * p;       <=> T const * p;       : *p is const
const shared_ptr<const T> p; ---> const T * const p; <=> T const * const p; : p and *p are const.

Điều tương tự đối với weak_ptrunique_ptr.


1
Bạn cũng đã trả lời một câu hỏi mà tôi có trong đầu về con trỏ thông thường (const T * so với T * const so với T const *). :) Tôi không đề cập đến điều đó vì tôi không muốn câu hỏi của mình trên SO quá rộng, và đây là câu hỏi phù hợp với nhiệm vụ hiện tại của tôi. Nhưng dù sao, tôi nghĩ tôi đã hiểu rất rõ. Cảm ơn!
Dave Lillethun

9
Tôi rất vui vì nó đã giúp. Một mẹo cuối cùng mà tôi sử dụng để ghi nhớ const T* p;', 'T const * p;T * const p. Xem *như là một dấu phân cách theo nghĩa là cái gì constlà cái nằm ở cùng một phía của *.
Cassio Neri

5
Quy tắc ngón tay cái của tôi là constluôn đề cập đến thứ ở bên trái của nó. Nếu không có gì ở bên trái, thì đó là thứ ở bên phải.
hochl

hochi - làm thế nào về const T * p; tương đương với T const * p;?
Vlad

Cassio, bạn có thể thêm rằng trong trường hợp trả về kiểu const shared_ptr <T>, nó không thể được sử dụng trong các hàm không phải const trong khi điều này không đúng với con trỏ const.
Vlad

2

boost::shared_ptr<Bar const> ngăn cản việc sửa đổi Bar đối tượng thông qua con trỏ được chia sẻ. Là một giá trị trả về, const in boost::shared_ptr<Bar> constcó nghĩa là bạn không thể gọi một hàm không phải const trên giá trị tạm thời được trả về; nếu nó dành cho một con trỏ thực (ví dụ Bar* const), nó sẽ hoàn toàn bị bỏ qua.

Nói chung, ngay cả ở đây, các quy tắc thông thường được áp dụng: constsửa đổi những gì đứng trước nó: in boost::shared_ptr<Bar const>, the Bar; trong boost::shared_ptr<Bar> const, đó là sự khởi tạo (biểu thức boost::shared_ptr<Bar>là const.


1
@gatopeich Vì vậy, bạn có thể làm được delete.
Marcin

@Marcin bạn có thể cộng tác không?
gatopeich

1
#Check this simple code to understand... copy-paste the below code to check on any c++11 compiler

#include <memory>
using namespace std;

class A {
    public:
        int a = 5;
};

shared_ptr<A> f1() {
    const shared_ptr<A> sA(new A);
    shared_ptr<A> sA2(new A);
    sA = sA2; // compile-error
    return sA;
}

shared_ptr<A> f2() {
    shared_ptr<const A> sA(new A);
    sA->a = 4; // compile-error
    return sA;
}

int main(int argc, char** argv) {
    f1();
    f2();
    return 0;
}

Tôi có thể đề nghị sử dụng std::make_shared()(kể từ C ++ 14).
Joel Bodenmann

0

Tôi muốn phân chia đơn giản dựa trên câu trả lời của @Cassio Neri:

#include <memory>

int main(){
    std::shared_ptr<int> i = std::make_shared<int>(1);
    std::shared_ptr<int const> ci;

    // i = ci; // compile error
    ci = i;
    std::cout << *i << "\t" << *ci << std::endl; // both will be 1

    *i = 2;
    std::cout << *i << "\t" << *ci << std::endl; // both will be 2

    i = std::make_shared<int>(3);
    std::cout << *i << "\t" << *ci << std::endl; // only *i has changed

    // *ci = 20; // compile error
    ci = std::make_shared<int>(5);
    std::cout << *i << "\t" << *ci << std::endl; // only *ci has changed

}
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.