- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
根据一个简单的、侵入式的引用计数对象系统,我有一个 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
继承自 CountedBase
当 T
时不会导致(虚假)错误不完整?
[通常免责声明:我知道以这种方式使用不完整类型可能存在不安全和/或 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
用一个不从 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/
我正在尝试用 Swift 编写这段 JavaScript 代码:k_combinations 到目前为止,我在 Swift 中有这个: import Foundation import Cocoa e
我是一名优秀的程序员,十分优秀!