`const shared_ptr<T>`和`shared_ptr<const T>`有什么区别?

158

我正在为 C++ 中的共享指针编写访问器方法,大意如下:

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

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

所以为了支持getBar()的常量性,返回类型应该是一个boost::shared_ptr,它防止修改指向的Bar。我猜测要返回的类型是shared_ptr<const Bar>,这样可以做到,而const shared_ptr<Bar>则会防止重新分配指针本身指向不同的Bar,但允许修改它所指向的Bar… 但是,我不确定。如果有人确切知道,请确认一下,或者如果我错了,请纠正我。谢谢!


4
没错,就是您说的那样。您可以查看*->运算符的文档来确认这一点。 - syam
2
T *constT const * 有什么区别吗?没有。 - user529758
4
完全不是。 const 通常修改其 _前面的内容,因此 T *const 是指向 Tconst 指针,而 T const* 是指向 const T 的指针。最好避免在没有前置内容的情况下使用 const - James Kanze
7
@JamesKanze,这就是H2CO3的观点:T *constT const *之间的区别与const shared_ptr<T>shared_ptr<const T>之间的区别相同。 - Jonathan Wakely
2
@H2CO3,我误解了你所说的“相同”。但我很好奇:你写的是T *const,那么为什么不写成shared_ptr<T> const呢?同样地,你写的是T const*,那么为什么不写成shared_ptr<T const>呢?为什么不保持正交性,在每个地方都加上const(因为在某些情况下必须在后面加上)? - James Kanze
显示剩余5条评论
4个回答

252
你是正确的。 shared_ptr<const T> p; 类似于 const T * p;(或等效于T const * p;),也就是指向的对象是const,而 const shared_ptr<T> p; 类似于 T* const p;,这意味着 pconst。总结一下:
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.

同样适用于weak_ptrunique_ptr

4
您还回答了我心中一直有的一个问题,关于普通指针(const T* vs. T* const vs. T const *)的区别。 :) 我没有提及这个问题,因为我不想让我的SO问题变得太广泛,而且这是与我当前任务相关的问题。无论如何,我现在认为我非常明白了。谢谢! - Dave Lillethun
11
我很高兴它有所帮助。我使用的最后一条提示是要记住const T* p;T const * p;T * const p。将星号*视为分隔符,因为在星号*的同侧是被const修饰的部分。 - Cassio Neri
6
我的经验法则是,const 始终指的是它左侧的东西。如果左侧没有任何东西,那么它所指的就是右侧的东西。 - hochl
1
hochi - const T * p; 和 T const * p; 等价吗? - Vlad
Cassio,针对返回类型为const shared_ptr<T>的情况,它不能用于非const函数,而对于const指针则不是这样。 - Vlad
经验法则是不要看 const 的位置,而是看 *;不要把 * 视为分隔符,而是将其视为指示左侧的任何内容都是指向的内容。由于 const intint const 是等效的,因此跟在任一者后面的 * 都是指向 const int 的指针。 - jensph

3
我想基于@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

}

2

boost::shared_ptr<Bar const>防止通过共享指针修改Bar对象。作为返回值,boost::shared_ptr<Bar> const中的const表示您不能对返回的临时变量调用非const函数;如果它是一个真正的指针(例如Bar* const),那么将被完全忽略。

通常情况下,即使在这里,也适用常规规则:const修改前面的内容:在boost::shared_ptr<Bar const>中,是Bar;在boost::shared_ptr<Bar> const中,则是实例化表达式boost::shared_ptr<Bar>本身是const。


1
@gatopeich 所以您可以“删除”它。 - Marcin
@Marcin,你能详细说明一下吗? - 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;
}

2
我可以建议使用 std::make_shared() (自 C++14 起)。 - Joel Bodenmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接