0

This is the first time I am trying to use std::unique_ptr but I am getting an access violation when using std::make_unique with large size .

what is the difference in this case and is it possible to catch this type of exceptions in c++ ?

void SmartPointerfunction(std::unique_ptr<int>&Mem, int Size)
{

   try
   {
      /*declare smart pointer */

      //Mem = std::unique_ptr<int>(new int[Size]); // using new  (No crash)
      Mem = std::make_unique<int>(Size);   // using make_unique    (crash when Size = 10000!!)

      /*set values*/
      for (int k = 0; k < Size; k++)
      {
        Mem.get()[k] = k;
      }

   }
   catch(std::exception& e)
   {
    std::cout << "Exception :" << e.what() << std::endl;
   }
}
9
  • 2
    That isn’t how you declare an array with unique_ptr. If you do a search on this site there are at least 3 questions in it. Commented Sep 19, 2022 at 2:54
  • 6
    You have a pointer pointing to a single int, not an array of ints, so you're writing out of bounds. You need std::unique_ptr<int[]> and std::make_unique<int[]>(Size). Commented Sep 19, 2022 at 2:56
  • 7
    What is the reason for trying to use std::unique_ptr for what should be a std::vector? And no, this error can not be caught. It is undefined behavior. Commented Sep 19, 2022 at 3:10
  • 3
    std::make_unique<T> creates one object of type T; std::make_unique<int>(Size) is not like new int[Size], it is like new int(size). Commented Sep 19, 2022 at 3:41
  • 2
    Because it so happened that the memory you were scribbling over was mapped, and so did not trigger a segmentation fault. By sheer luck, this time you didn't overwrite anything else important that would have made your program fail in a noticeable way. C++ implementations usually make no promises of error checking, and code that causes undefined behavior will very often appear to work. Commented Sep 19, 2022 at 4:12

2 Answers 2

1

When you invoke std::make_unique<int>(Size), what you actually did is allocate a memory of size sizeof(int) (commonly 4bytes), and initialize it as a int variable with the number of Size. So the size of the memory you allocated is only a single int, Mem.get()[k] will touch the address which out of boundary.

But out of bounds doesn't mean your program crash immediately. As you may know, the memory address we touch in our program is virtual memory. And let's see the layout of virtual memory addresses.

enter image description here

You can see the memory addresses are divided into several segments (stack, heap, bss, etc). When we request a dynamic memory, the returned address will usually located in heap segment (I use usually because sometimes allocator will use mmap thus the address will located at a memory shared area, which is located between stack and heap but not marked on the diagram).

The dynamic memory we obtained are not contiguous, but heap is a contiguous segment. from the OS's point of view, any access to the heap segment is legal. And this is what the allocator exactly doing. Allocator manages the heap, divides the heap into different blocks. These blocks, some of which are marked "used" and some of which are marked "free". When we request a dynamic memory, the allocator looks for a free block that can hold the size we need, (split it to a small new block if this free block is much larger than we need), marks it as used, and returns its address. If such a free block cannot be found, the allocator will call sbrk to increase the heap.

Even if we access address which out of range, as long as it is within the heap, the OS will regard it as a legal operation. Although it might overwrite data in some used blocks, or write data into a free block. But if the address we try to access is out of the heap, for example, an address greater than program break or an address located in the bss. The OS will regard it as a "segment fault" and crash immediately.

So your program crashing is nothing to do with the parameter of std::make_unique<int>. It just so happens that when you specify 1000, the addresses you access are out of the segment.

Sign up to request clarification or add additional context in comments.

1 Comment

I’d add: It’s a code smell if you have to call .get(). In this case, because std::unique_ptr<T[]> has an operator[], so if you use that, you are all set (although prefer std::vector unless you have good reason to need std::unique_ptr<T[]>).
1
std::make_unique<int>(Size);

This doesn't do what you are expecting! It creates single int and initializes it into value Size!

I'm pretty sure your plan was to do:

auto p = std::make_unique<int[]>(Size)

Note extra brackets. Also not that result type is different. It is not std::unique_ptr<int>, but std::unique_ptr<int[]> and for this type operator[] is provided!

Fixed version, but IMO you should use std::vector.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.