我正在使用这个库创建自定义智能指针,我可以在其中跟踪它们的堆栈调用和生命周期。
这是我的代码:
#ifndef VIBRANIUM_CORE_VEMEMORY_H
#define VIBRANIUM_CORE_VEMEMORY_H
#include <iostream>
#include <vector>
#include <ctime>
#define TRACK_SHARED_PTR_LEAKS 1
#if TRACK_SHARED_PTR_LEAKS
#define B_STACKTRACE_IMPL
#include <mutex>
#include <unordered_set>
#include <algorithm>
#include <iomanip>
#include <xmem/atomic_ref_count.hpp>
#include <xmem/common_control_block.hpp>
#include <xmem/ostream.hpp>
#include <xmem/basic_shared_from.hpp>
#include "xmem/shared_ptr.hpp"
class b_stacktrace_tag;
namespace VE {
struct free_deleter {
void operator()(void* ptr) { free(ptr); }
};
struct stacktrace {
static constexpr bool init = true;
stacktrace(bool init = false) {
if (init) record();
}
xmem::unique_ptr<b_stacktrace_tag, free_deleter> m_trace;
explicit operator bool() { return !!m_trace; }
void record();
friend std::ostream& operator<<(std::ostream& out, const stacktrace& st);
};
class MemoryControlBlock : protected xmem::control_block_base<xmem::atomic_ref_count> {
public:
using cb_type = MemoryControlBlock;
struct entry {
const void* ptr;
stacktrace trace;
};
private:
std::time_t m_creation_time;
stacktrace m_creation_trace;
mutable std::mutex m_mutex;
std::vector<entry> m_active_strong;
public:
MemoryControlBlock()
: m_creation_time(std::time(nullptr))
, m_creation_trace(stacktrace::init)
{}
const time_t& creation_time() const { return m_creation_time; }
const stacktrace& creation_trace() const { return m_creation_trace; }
void log_active_strong(std::ostream& out) const {
std::lock_guard _l(m_mutex);
for (auto& ref : m_active_strong) {
out << ref.ptr << ":\n";
out << ref.trace << "\n";
}
}
using super = xmem::control_block_base<xmem::atomic_ref_count>;
void on_new_strong(const void* src) {
std::lock_guard _l(m_mutex);
auto& e = m_active_strong.emplace_back();
e.ptr = src;
e.trace.record();
}
void on_destroy_strong(const void* src) {
std::lock_guard _l(m_mutex);
auto f = std::find_if(m_active_strong.begin(), m_active_strong.end(), [&](const entry& e) { return e.ptr == src; });
m_active_strong.erase(f);
}
void on_new_weak(const void* /*src*/) {
// std::lock_guard _l(m_mutex);
}
void on_destroy_weak(const void* /*src*/) {
// std::lock_guard _l(m_mutex);
}
void init_strong(const void* src) noexcept {
super::init_strong(src);
on_new_strong(src);
}
void inc_strong_ref(const void* src) noexcept {
super::inc_strong_ref(src);
on_new_strong(src);
}
void dec_strong_ref(const void* src) noexcept {
on_destroy_strong(src);
super::dec_strong_ref(src);
}
bool inc_strong_ref_nz(const void* src) noexcept {
if (super::inc_strong_ref_nz(src)) {
on_new_strong(src);
return true;
}
return false;
}
using super::strong_ref_count;
void transfer_strong(const void* dest, const void* src) {
super::transfer_strong(dest, src);
on_new_strong(dest);
on_destroy_strong(src);
}
void inc_weak_ref(const void* src) noexcept {
super::inc_weak_ref(src);
on_new_weak(src);
}
void dec_weak_ref(const void* src) noexcept {
on_destroy_weak(src);
super::dec_weak_ref(src);
}
void transfer_weak(const void* dest, const void* src) {
super::transfer_weak(dest, src);
on_new_weak(dest);
on_destroy_weak(src);
}
};
using bookkeeping_control_block_factory = xmem::control_block_factory<MemoryControlBlock>;
template <typename T>
using shared_ptr = xmem::basic_shared_ptr<MemoryControlBlock, T>;
template <typename T>
using weak_ptr = xmem::basic_weak_ptr<MemoryControlBlock, T>;
template <typename T>
using enable_shared_from_this = xmem::basic_enable_shared_from_this<MemoryControlBlock, T>;
template<class T, class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept
{
auto p = static_cast<typename shared_ptr<T>::element_type*>(r.get());
return shared_ptr<T>{r, p};
}
template <class T, class U>
shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const& r) noexcept
{
if (auto p = dynamic_cast<typename shared_ptr<T>::element_type*>(r.get()))
return shared_ptr<T>{r, p};
else
return shared_ptr<T>{};
}
template <typename T, typename... Args>
[[nodiscard]] shared_ptr<T> make_shared(Args&&... args) {
return shared_ptr<T>(bookkeeping_control_block_factory::make_resource_cb<T>(std::allocator<char>{}, std::forward<Args>(args)...));
}
template <typename T>
[[nodiscard]] auto make_shared_ptr(T&& t) -> shared_ptr<std::remove_reference_t<T>>
{
return xmem::make_shared_ptr(t);
}
}
#else
#include <memory>
namespace VE
{
using std::shared_ptr;
using std::weak_ptr;
using std::make_shared;
using std::enable_shared_from_this;
using std::static_pointer_cast;
using std::dynamic_pointer_cast;
}
#endif
#endif //VIBRANIUM_CORE_VEMEMORY_H
比我有这个代码:
#pragma once
#include "Memory/VEMemory.h"
template <class Base>
class enable_shared_from_base : public VE::enable_shared_from_this<Base>
{
protected:
template <class Derived>
VE::shared_ptr<Derived> shared_from_base()
{
return VE::static_pointer_cast<Derived>(this->shared_from_this());
}
};
我创建了这个类:
namespace VE::Nodes {
class VENode : public enable_shared_from_base<VE::Nodes::VENode> {
typedef std::set<VE::shared_ptr<VE::Components::VEComponent>> Components;
friend class VE::Components::ComponentManager;
public:
explicit VENode(VEId veId);
VENode(VENode const &ve_node, VEId veId);
virtual ~VENode();
virtual void Initialize();
VE::shared_ptr<Transform> transform;
void ComponentsPacket(packet_t& packet);
void SetParent(VE::shared_ptr<VE::Nodes::VENode> parent)
{
parent_ = parent;
}
VE::shared_ptr<VE::Nodes::VENode> GetParent() { return parent_;}
};
}
因此,我执行以下操作:
void VE::Nodes::VENode::Initialize()
{
this->guid = VENodeManager->CreateGUID(id_.GetVEMask());
try {
auto node = shared_from_this();
VENodeManager->AddNode(node);
} catch (const std::bad_weak_ptr& e) {
std::cerr << "Failed to obtain shared_ptr: " << e.what() << std::endl;
// Additional handling or fallback
}
}
在函数
Initalize()
中,node
始终为空。这是为什么?
是否有任何指南或示例显示
shared_from_this
和 enable_shared_from_this
的用法?
shared_from_this
的总体设计是enable_shared_from_this
父类为自己存储一个weak_ptr
。然后当你请求 shared_from_this
时,它实际上只是在 .lock()
上调用 weak_ptr
。
当您创建一个包装对象的共享指针时,
weak_ptr
就会被创建——无论是在shared_ptr<T>(T*)
的构造函数中,还是在make_shared_ptr
函数中。
基本上,如果您尚未在程序中的某个位置创建共享指针,则
shared_from_this
无法返回共享指针。