遍历 unique_ptr 拥有的内存会出现段错误
traversing memory owned by a unique_ptr gives segfault
为了不用记住删除,我们使用unique_ptr来管理内存。
我们的印象是我们可以在内存中写入和读取,只是删除取决于智能指针。但是,以下代码在 i=7220 上崩溃并出现段错误。
怎么了?
#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);
这会使用值 n
.
动态分配 one uint64_t
你想要:
unique_ptr<uint64_t[]> mem = make_unique<uint64_t[]>(n);
这个特化分配了一个 array of uint64_t
with n
elements, and has an operator[]
overload which makes below:
for (int i = 0; i < n; i++)
mem[i] = i;
所以,没必要uint64_t* p1 = mem.get();
unique_ptr<uint64_t>
是指向单个 uint64_t
值的指针。为了让它存储一个数组,你需要使用 array of unknown bound 语法:
unique_ptr<uint64_t[]> mem = make_unique<uint64_t[]>(n);
或者只是
auto mem{make_unique<uint64_t[]>(n)};
请注意,此变体重载了运算符 [],因此无需创建中间原始指针 uint64_t* p1 = mem.get();
除了提到的其他答案的修复之外,您可能不想在这里使用make_unique
。 make_unique
会将每个元素清零(4000 万个整数!),然后您会立即覆盖它们。您的选择是使用需要 C++20 的 make_unique_for_overwrite
,或使用 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);
}
为了不用记住删除,我们使用unique_ptr来管理内存。 我们的印象是我们可以在内存中写入和读取,只是删除取决于智能指针。但是,以下代码在 i=7220 上崩溃并出现段错误。
怎么了?
#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);
这会使用值 n
.
uint64_t
你想要:
unique_ptr<uint64_t[]> mem = make_unique<uint64_t[]>(n);
这个特化分配了一个 array of uint64_t
with n
elements, and has an operator[]
overload which makes below:
for (int i = 0; i < n; i++)
mem[i] = i;
所以,没必要uint64_t* p1 = mem.get();
unique_ptr<uint64_t>
是指向单个 uint64_t
值的指针。为了让它存储一个数组,你需要使用 array of unknown bound 语法:
unique_ptr<uint64_t[]> mem = make_unique<uint64_t[]>(n);
或者只是
auto mem{make_unique<uint64_t[]>(n)};
请注意,此变体重载了运算符 [],因此无需创建中间原始指针 uint64_t* p1 = mem.get();
除了提到的其他答案的修复之外,您可能不想在这里使用make_unique
。 make_unique
会将每个元素清零(4000 万个整数!),然后您会立即覆盖它们。您的选择是使用需要 C++20 的 make_unique_for_overwrite
,或使用 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);
}