【发布时间】:2021-09-09 10:35:39
【问题描述】:
我已经实现了一个类 reference<T>,它跟踪对从 reference_countable 派生的 T 的引用量。
关于转发声明reference<T> 的T,我有一个问题,类似于std::unique_ptr<T>。对于std::unique_ptr<T>,问题来自于未知的析构函数,因此您只需将类的析构函数放入 cpp 文件中,如下所示:
标题:
class MyClass;
class A
{
std::unique_ptr<MyClass> my_class;
}
实施:
A:~A() = default;
但是,在我的版本中,std::unique_ptr<MyClass> 被 reference<MyClass> 替换,reference_countable 也必须递减和递增。当MyClass 仅被前向声明时,这要求我还将A 的复制分配和复制构造函数放入cpp 文件中。
有没有办法避免将这三个函数的实现放在所有具有reference<T> 成员的类的 cpp 文件中?
我试图尽可能简单地描述它,但为了更详细,这里是问题的简单版本。具体来说,需要在a.cpp中定义A的copy-constructor。
my_class.h
#pragma once
#include "minimal_ref_counter.h"
class MyClass : public minimal_reference_countable
{
};
啊。
#pragma once
#include "minimal_ref_counter.h"
class MyClass;
class A
{
public:
A();
~A();
A(const A&);
minimal_reference_counter<MyClass> my_class;
};
a.cpp
#include "test.h"
#include "myclass.h"
A::A()
: my_class(new MyClass())
{}
A::~A() = default;
A::A(const A&) = default;
some_other_code.cpp
#include "a.h"
void some_function()
{
A a1;
A a2 = a1; // this code does not compile without the copy assignment operator beeing implemented externally.
}
minimal_ref_counter.h
#pragma once
#include <atomic>
class minimal_reference_countable
{
template<typename T>
friend class minimal_reference_counter;
std::atomic_int m_references = 0;
auto reference_count() const { return m_references.load(); }
void decrement() { --m_references; }
void increment() { ++m_references; }
};
template<typename T>
class minimal_reference_counter
{
public:
minimal_reference_counter(T* t = nullptr)
{
assign(t);
}
~minimal_reference_counter()
{
reset();
}
minimal_reference_counter(const minimal_reference_counter& r)
{
*this = r;
}
minimal_reference_counter(minimal_reference_counter&& r)
{
*this = std::move(r);
}
minimal_reference_counter& operator=(const minimal_reference_counter& r)
{
assign(r.m_ptr);
return *this;
}
minimal_reference_counter& operator=(minimal_reference_counter&& r)
{
assign(r.m_ptr);
r.reset();
return *this;
}
void reset()
{
if (!m_ptr) return;
m_ptr->decrement();
if (m_ptr->reference_count() == 0)
{
delete m_ptr;
}
m_ptr = nullptr;
}
private:
void assign(T* ptr)
{
reset();
m_ptr = ptr;
if (m_ptr) m_ptr->increment();
}
T* m_ptr = nullptr;
};
【问题讨论】:
-
我更好奇为什么你需要创建这个
reference<T>类?它解决了std::shared_ptr<T>没有解决什么问题? -
您误解了为什么析构函数进入 cpp 文件:它只是将实例化
std::unique_ptr::~unique_ptr(或实际上是std::default_delete::operator())推迟到MyClass::~MyClass可见之后 -
然而,如果你有一个
reference_countable基类,你不需要知道任何派生的MyClass来使用它。为什么不在operator*或其他地方存储一个基类指针并处理向下转换? -
@Someprogrammerdude 目标是有一个更轻量级的 shared_ptr 版本(甚至可能有一个非线程安全的版本)。
-
@Useless 前向
MyClass不知道有reference_countable基类。所以不能调用递减的增量。我必须存储 2 个指针,指向MyClass和一个指向reference_countable,当唯一的目标是不必将复制分配/构造函数放在 cpp 文件中时,我不想这样做。
标签: c++ smart-pointers forward-declaration type-erasure