gpt4 book ai didi

c++ - 在可能不完整的类型上进行可选的安全检查

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:43:38 25 4
gpt4 key购买 nike

根据一个简单的、侵入式的引用计数对象系统,我有一个 template<typename T> class Handle , 这意味着用 CountedBase 的子类实例化. Handle<T>持有指向 T 的指针, 它的析构函数调用 DecRef (在 CountedBase 中定义)在该指针上。

通常,这会在尝试使用前向声明限制 header 依赖性时导致问题:

#include "Handle.h"

class Foo; // forward declaration

struct MyStruct {
Handle<Foo> foo; // This is okay, but...
};

void Bar() {
MyStruct ms;
} // ...there's an error here, as the implicit ~MyStruct calls
// Handle<Foo>::~Handle(), which wants Foo to be a complete
// type so it can call Foo::DecRef(). To solve this, I have
// to #include the definition of Foo.

作为解决方案,我重写了 Handle<T>::~Handle()如下:

template<typename T>
Handle<T>::~Handle() {
reinterpret_cast<CountedBase*>(m_ptr)->DecRef();
}

请注意,我使用的是 reinterpret_cast这里不是 static_cast , 自 reinterpret_cast不需要 T 的定义要完整。当然,它也不会为我执行指针调整......但只要我小心布局( T 必须有 CountedBase 作为它的最左边的祖先,不能从它虚拟继承,并且在几个不寻常的平台,一些额外的 vtable 魔法是必要的),这是安全的。

不过,如果我能得到额外的 static_cast 层,那将是真正的好事。尽可能安全。在实践中,T 的定义通常Handle::~Handle 处完成被实例化,这是仔细检查 T 的最佳时机实际上继承自CountedBase .如果它不完整,我无能为力...但如果它完整,进行完整性检查会很好。

最后,这让我们想到了我的问题:有什么方法可以编译时检查 T继承自 CountedBaseT 时不会导致(虚假)错误不完整?

[通常免责声明:我知道以这种方式使用不完整类型可能存在不安全和/或 UB 方面。尽管如此,在进行了大量的跨平台测试和分析之后,我确定这是考虑到我的用例的某些独特方面的最实用的方法。我对编译时检查问题感兴趣,而不是一般的代码审查。]

最佳答案

sizeof 上使用 SFINAE检查类型是否完整:

struct CountedBase {
void decRef() {}
};

struct Incomplete;
struct Complete : CountedBase {};

template <std::size_t> struct size_tag;

template <class T>
void decRef(T *ptr, size_tag<sizeof(T)>*) {
std::cout << "static\n";
static_cast<CountedBase*>(ptr)->decRef();
}

template <class T>
void decRef(T *ptr, ...) {
std::cout << "reinterpret\n";
reinterpret_cast<CountedBase*>(ptr)->decRef();
}

template <class T>
struct Handle {
~Handle() {
decRef(m_ptr, nullptr);
}

T *m_ptr = nullptr;
};

int main() {
Handle<Incomplete> h1;
Handle<Complete> h2;
}

输出(注意销毁顺序颠倒):

static
reinterpret

Live on Coliru

用一个不从 CountedBase 派生的完整类型尝试它产量:

main.cpp:16:5: error: static_cast from 'Oops *' to 'CountedBase *' is not allowed

话虽如此,我认为更优雅(也更明确)的方法是引入类模板 incomplete<T> , 这样 Handle<incomplete<Foo>>编译为 reinterpret_cast ,以及其他任何尝试 static_cast .

关于c++ - 在可能不完整的类型上进行可选的安全检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31831577/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com