简体   繁体   中英

traversing memory owned by a unique_ptr gives segfault

In order not to have to remember to delete, we are using unique_ptr to manage the memory. We were under the impression that we can write and read in the memory, just that deletion is up to the smart pointer. However, the following code crashes on i=7220 with a segfault.

What is wrong?

#include <memory>
using namespace std;

int main() {
  const uint32_t n = 40000000;
  uint64_t*p = new uint64_t[n]; // this works, but we have to delete the memory or leak
  for (int i = 0; i < n; i++)
    p[i] = i;

  unique_ptr<uint64_t> mem = make_unique<uint64_t>(n);

  uint64_t* p1 = mem.get();
  for (int i = 0; i < n; i++) // this crashes at i=7220
    p1[i] = i;

  return 0;
}
unique_ptr<uint64_t> mem = make_unique<uint64_t>(n);

This allocates one uint64_t dynamically with the value n .

You want:

unique_ptr<uint64_t[]> mem = make_unique<uint64_t[]>(n);

This specialization allocates an array of uint64_t with n elements, and has an operator[] overload which makes the below possible:

for (int i = 0; i < n; i++)
    mem[i] = i;

So, there's no need to do uint64_t* p1 = mem.get();

unique_ptr<uint64_t> is a pointer to a single uint64_t value. In order to make it store an array you need to use array of unknown bound syntax:

unique_ptr<uint64_t[]> mem = make_unique<uint64_t[]>(n);

or just

auto mem{make_unique<uint64_t[]>(n)};

Note that this variant overloads operator [] so there is no need to create an intermediate raw pointer uint64_t* p1 = mem.get();

Aside from the fix other answers mentioned, you likely don't want to use make_unique here. make_unique will zero-out every single element (40 million ints.) and you immediately overwrite them. Your options are to use make_unique_for_overwrite which requires C++20, or to use new :

#include <cstdint>  // for uint64_t
#include <memory>   // for unique_ptr, unique_ptr<>::pointer
#include <numeric>  // for iota

int main() {
  auto const n = 40'000'000;
  auto const p = std::unique_ptr<std::uint64_t[]>{new std::uint64_t[n]};
  std::iota(p.get(), p.get() + n, 0);
}

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