0

I want to create some continuous memory, and use bunch of shared_ptr pointing to them.

int main() {
  int *arr = new int[5];
  for (int i = 0; i < 5; i++) {
    std::shared_ptr<int> ptr(&arr[i]);
  }// when the loop scope end, the shared_ptr will be destroyed. 
};

this code will give an error:

pointer being freed was not allocated

my expectation: when the scope of loop end, the shared_ptr will be destroy, and the element in array will be destroyed successively.

But it seems that when the first pointer is destroyed, the whole array is freed.

I also tried std::allocator, still not work.

So is there any way that can allocate continuous memory, and I can use shared_ptr pointing to each of them, then when the first element is freed, the whole memory won't be freed together?

Ziqi Liu
  • 2,037
  • 1
  • 18
  • 41
  • Please show any code which frees anything. Some of it seems wrong. Maybe directly try for a [mcve]. – Yunnosch Aug 03 '18 at 06:15
  • 5
    *Why* do you want to use a shared pointer to a single element? What is the *actual* problem you try to solve? And if you had [read about `std::shared_ptr`](http://en.cppreference.com/w/cpp/memory/shared_ptr) you would know that it tries to `delete` the memory it wraps. – Some programmer dude Aug 03 '18 at 06:15
  • 2
    @Yunnosch That would be the `ptr` object going out of scope at the end of each loop. – Some programmer dude Aug 03 '18 at 06:15
  • 1
    Possible duplicate of [Creating shared\_ptr from raw pointer](https://stackoverflow.com/questions/4665266/creating-shared-ptr-from-raw-pointer) – neuront Aug 03 '18 at 06:17
  • 1
    An allocation cannot be deallocated in pieces, and that's what storing pointers to different pieces of a single allocation in smart pointers would do. You could have a wrapper that contained a shared pointer to the whole array and a reference to a specific element. This way all of the shared pointers to the array must die before the array will be freed. – user4581301 Aug 03 '18 at 06:22

2 Answers2

4

Its an "interesting" thing to want to do but if you really want to do it you can use the shared_ptr's aliasing constructor.

int main() {
  std::shared_ptr<int[]> arr(new int[5]);
  for (int i = 0; i < 5; i++) {
    std::shared_ptr<int> ptr(arr,&arr[i]);
  }
};

Without c++17 you need to do a little more:

int main() {
    std::shared_ptr<int[]> arr(new int[5], std::default_delete<int[]> {});
    for (int i = 0; i < 5; i++) {
        std::shared_ptr<int> ptr(arr, &arr.get()[i]);
    }
};

The array will be deleted when the last element shared_ptr is destroyed (assuming the array shared_ptr itself has already been destroyed/reset).

Alan Birtles
  • 22,711
  • 4
  • 22
  • 44
3

You are misusing shared_ptr. The memory you allocated was attributed with operator new[], it should thus be freed with operator delete[].

Furthermore, since the allocated object is an array, any ownership semantics should be applied to the whole array and not divided across its elements!

You can achieve by specifying a custom deleter for your shared_ptr: (C++11/14)

std::shared_ptr<int> arr_ptr(new int[5], std::default_delete<int[]> {});

Or simply using an array type specialization of shared_ptr (C++17):

std::shared_ptr<int[]> arr_ptr(new int[5]); // Will call delete[] upon destruction.
Rerito
  • 5,556
  • 17
  • 45
  • 2
    [The correct way to use a shared pointer to an array is like `std::shared_ptr`](https://stackoverflow.com/a/13062069/1171191). – BoBTFish Aug 03 '18 at 06:24
  • @BoBTFish That's what I tried first, but to no avail: http://coliru.stacked-crooked.com/a/106828ec577354cf – Rerito Aug 03 '18 at 06:27
  • 1
    @Rerito I smell outdated Clang on Coliru. It works on GCC: http://coliru.stacked-crooked.com/a/a9bd51b8056a6f5f – HolyBlackCat Aug 03 '18 at 06:28
  • 1
    Alright, integrated the C++17 solution to the answer! – Rerito Aug 03 '18 at 06:32
  • Fair point, it's a bit early to assume C++17 support everywhere. Good to show both options. – BoBTFish Aug 03 '18 at 06:48
  • And in C++20, you can use `std::shared_ptr arr_ptr = std::make_shared(5);` instead of calling `new int[5]` separately and risk a leak if the `shared_ptr` constructor throws an exception. – Remy Lebeau Aug 03 '18 at 07:35