我有一些代码几乎什么都不做,但它是以一种复杂的方式做的。最重要的是,它不分配任何东西。所有数据都在堆栈上。它可以与许多版本的gcc和clang配合使用,无论是在我的计算机上还是在Godbolds编译器资源管理器上。如果我使用
-std=20
或
-std=17
。这就是我的编译方式。
g++ -std=c++17 -g -O0 -fsanitize=address -fno-omit-frame-pointer leaking_memory.cpp
但是,如果我替换的默认副本ctor
arena_ptr
在手动实现的情况下,消毒程序将报告内存泄漏。
我可以在我的电脑上用不同版本的gcc和clang来复制这一点。我也可以在Godbold上用不同版本的gcc复制这一点,但不能用clang。
至关重要的是,如果不复制
竞技场_ptr
转换为lambda捕获(请参见函数
f
在下面我想了解这一点。这是我的代码:
#include <memory>
#include <memory_resource>
#include <functional>
struct arena {
alignas(64) std::byte memory_[1000000] = {std::byte{}};
std::byte *pos_ = memory_;
template<typename T, typename... Args>
T *new_object(Args &&...args) {
auto *ptr = new (pos_) T(std::forward<Args>(args)...);
pos_ += sizeof(T) + (size_t(pos_) % 8UL);
return ptr;
}
};
arena * a_ptr = nullptr;
template<typename T>
struct arena_ptr {
T *value_ptr_ = nullptr;
explicit arena_ptr(T *value_ptr_) : value_ptr_(value_ptr_) {}
arena_ptr() = delete;
arena_ptr(arena_ptr const &) = default;
//inline arena_ptr(arena_ptr const &other) : value_ptr_(other.value_ptr_) {}
arena_ptr(arena_ptr &&) = delete;
arena_ptr &operator=(arena_ptr const &) = delete;
arena_ptr &operator=(arena_ptr &&) = delete;
~arena_ptr() = default;
};
template<typename T, typename... Args>
arena_ptr<T> make_arena_ptr(Args &&...args) {
T *ptr = a_ptr->new_object<T>(std::forward<Args>(args)...);
return arena_ptr(ptr);
}
struct TT {};
struct CC {
using PP = std::function<bool()>;
PP pp;
CC(CC const &) = default;
explicit CC(PP pp) : pp(std::move(pp)) {}
};
auto f(arena_ptr<TT> left) {
auto f = [left]() { return true; };
return make_arena_ptr<CC>(f);
}
auto g() {
auto int_number = []() { return make_arena_ptr<TT>(); };
return f(int_number());
}
int main() {
arena a;
a_ptr = &a;
auto program = g();
}
这是当我使用的手动ctor定义时的输出
竞技场_ptr
:
=================================================================
==1==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 8 byte(s) in 1 object(s) allocated from:
#0 0x7f2af4f9c528 in operator new(unsigned long) (/opt/compiler-explorer/gcc-13.1.0/lib64/libasan.so.8+0xdb528) (BuildId: c9b24be17e4cbd04bdb4891782c4425e47a9259a)
#1 0x401b44 in _M_create<f(arena_ptr<TT>)::<lambda()>&> /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/std_function.h:161
#2 0x401a25 in _M_init_functor<f(arena_ptr<TT>)::<lambda()>&> /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/std_function.h:215
#3 0x401961 in function<f(arena_ptr<TT>)::<lambda()>&> /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/std_function.h:449
#4 0x40172f in new_object<CC, f(arena_ptr<TT>)::<lambda()>&> /app/example.cpp:10
#5 0x401607 in make_arena_ptr<CC, f(arena_ptr<TT>)::<lambda()>&> /app/example.cpp:35
#6 0x4012f1 in f(arena_ptr<TT>) /app/example.cpp:54
#7 0x401467 in g() /app/example.cpp:59
#8 0x4015a8 in main /app/example.cpp:65
#9 0x7f2af491a082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)
SUMMARY: AddressSanitizer: 8 byte(s) leaked in 1 allocation(s).