Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

segment fault for a simple std::shared_ptr construction case

From cppreference I learn that there is a constructor for std::shared_ptr:

template< class Y > explicit shared_ptr( Y* ptr );

And I tried a piece of code as follows:

#include <string>
#include <memory>
#include <iostream>

int main(void) {
  /// block 1
  {
    std::shared_ptr<std::string> s1(new std::string("good"));
    std::shared_ptr<std::string> s2(s1.get()); /// s2
    std::cerr << s2.use_count() << std::endl;
  }
  /// block 2
  {
    std::shared_ptr<int> i1(new int(1));
    std::shared_ptr<int> i2(i1.get());  ///  i2
    std::cerr << i2.use_count() << std::endl;
  }
  return 0;
}

It causes segment fault for block 1 but not for block 2, but both use_count are 1. The difference I can think about is that that int is a primitive type while std::string is managed by allocator.

I read bits/shared_ptr.h of gcc-4.9 and find that there is a post condition for this constructor:

use_count() == 1 && get() == __p

Question 1:

Should std::shared_ptr NOT constructed with a raw pointer that has been referenced by another smart pointer? In this sense, is the preferred way to use this constructor as follow?

std::shared_ptr<T>(new T(...));

Question 2:

Does the standard has explicit requirement for this constructor, or this post condition is ONLY for libstdc++?

like image 226
Hongxu Chen Avatar asked Dec 15 '22 20:12

Hongxu Chen


1 Answers

Both of these cases are invalid uses of std::shared_ptr.

You cannot pass the same raw pointer to two std::shared_ptr constructors and expect well-defined results. Both std::shared_ptrs will believe that they own that pointer, and will attempt to delete it when they go out of scope.

This is a double free, and is invalid.

If you want to have two std::shared_ptrs that manage the same object, you can construct one of them with a raw pointer (or, better yet, use std::make_shared), and then copy construct/assign the second one from the first one. This way the memory will only be deallocated (and the destructor for the object fired) when the last of those std::shared_ptrs goes out of scope.

The reason you're getting a segmentation fault in the first case, and not the second one, is likely because int is a trivial type, and therefore you're not looking through a freed pointer to run the destructor of int, because it doesn't have one.

like image 91
Robert Allan Hennigan Leahy Avatar answered Feb 06 '23 15:02

Robert Allan Hennigan Leahy