简体   繁体   中英

Why I am able to assign constant shared_ptr to non constant shared_ptr in C++?

I thought I can't assign a constant shared_ptr to a non-constant shared_ptr . But surprisingly I am able to assign as below and it is working fine.

#include <iostream>
#include <memory>

using namespace std;

int main()
{
    const std::shared_ptr<const string> a = std::make_shared<const string>("Hello world");

    std::shared_ptr<const string> b = a;
    cout << "a count " << a.use_count() << ", b count " << b.use_count() << endl;
    return 0;
}

.use_count() is getting printed as 2. Can any one please help me to understand how I am able to do it?

The situation in your code is exactly the same as here:

const int a = 5;
int b = a;
std::cout << "a=" << a ", b=" << b << std::endl; // a=5, b=5
b = 10;
std::cout << "a=" << a ", b=" << b << std::endl; //a=5, b=10

Not particularly surprising, right? I had const int , and I used it to initialize non-const int . The value from a got copied into b and a wasn't modified at all.

Same occurs with const std::shared_ptr . Copy-constructing another object is not modifying the original object.

use_count can be changed, because it's not a member of std::shared_ptr class. std::shared_ptr requires two memory blocks allocated on the heap - a control block and actual object block.
Every std::shared_ptr instance only stores a pointer to the control block and to the actual object. The control block stores use count (number of std::shared_ptr s that hold the pointer to it).

When you copy std::shared_ptr , it increments the use count in control block and gets the same two pointers. When std::shared_ptr dies, it decrements use count (and deletes both blocks if use count reaches 0).

So, to sum up: use count is not a member of std::shared_ptr , and as such it can change even for const std::shared_ptr (otherwise const std::shared_ptr would be quite useless).

The string that a and b are pointing at is still const in both cases, but the pointer b isn't, so you could change what b is pointing at:

std::shared_ptr<const string> b = a;
b = std::make_shared<const string>("New string");

But you can't change what a is pointing at (since a is const ):

a = std::make_shared<const string>("Won't compile");

Similarly:

const char* const a = "Hello world";
const char* b = a;

const char* c = "Something else";
b = c;    // the pointer "b" is not const and can be changed
// a = c; // won't compile since the pointer "a" itself is const

Let's simplify:

#include <iostream>
#include <memory>

int main() {
    const auto a = std::make_shared<const std::string>("Hello world");

    auto b = a;
    std::cout << "a count " << a.use_count() << ", b count " << b.use_count() << "\n";
}

Types allowing copy-construction from a mutable object, but not from a constant one, are very rare and all user-defined. Mostly, they pre-date move-semantics, and thus C++11.
std::shared_ptr , introduced with C++11, is not such an exception. Why should it?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM