【发布时间】:2015-10-08 23:09:39
【问题描述】:
我目前正在编写一些使用智能指针的代码,其中有必要在多个点将这些指针转换为它们的基本类型并将它们作为 const 参数传递给函数。目前我正在使用 shared_ptr 和标准指针转换函数来实现这一点,但这似乎效率低下(因为每次转换至少需要一个 CAS)并且还具有误导性(因为我们没有对共享关系进行建模,所以父级是唯一的所有者对象)。
因此我想出了以下方法,但想检查它是否确实安全,或者是否有一些边缘情况会破坏它?
template <typename ToType, typename FromType>
class FTScopedCastWrapper {
public:
explicit FTScopedCastWrapper(std::unique_ptr<FromType>& p) : from_ptr_(&p) {
auto d = static_cast<ToType *>(p.release());
to_ptr_ = std::unique_ptr<ToType>(d);
}
~FTScopedCastWrapper() {
auto d = static_cast<FromType *>(to_ptr_.release());
(*from_ptr_) = std::unique_ptr<FromType>(d);
}
const std::unique_ptr<ToType>& operator()() {
return to_ptr_;
}
// Prevent allocation on the heap
void* operator new(size_t) = delete;
void* operator new(size_t, void*) = delete;
void* operator new[](size_t) = delete;
void* operator new[](size_t, void*) = delete;
private:
std::unique_ptr<FromType>* from_ptr_;
std::unique_ptr<ToType> to_ptr_;
};
template <typename ToType, typename FromType>
FTScopedCastWrapper<ToType, FromType> FTScopedCast(std::unique_ptr<FromType>& p) {
return FTScopedCastWrapper<ToType, FromType>(p);
}
那么预期的用途是
void testMethod(const std::unique_ptr<Base>& ptr) {
// Do Stuff
}
auto ptr = std::make_unique<Derived>();
testMethod(FTScopedCast<Base>(ptr)());
删除器不会被传递,因为这样做会阻止向上转换。这样做也没有意义,因为无论如何都不会在创建的智能指针上调用删除器。
堆上的分配被阻止,因为它可能允许包装器比它包装的指针寿命更长,复制被 std::unique_ptr 成员阻止,标准销毁顺序将确保原始指针返回到它之前的原始智能指针被销毁,即使它被声明在与包装器相同的范围内。
我知道这不是线程安全的,但我认为在线程之间共享 unique_ptr 会违反其单一所有者的合同。
【问题讨论】:
-
考虑翻转逻辑并让对象调用函数。他们知道自己的类型,所以不再有演员表。
-
如果
testMethod不打算影响所有权,那么为什么还要费心让它引用一个unique_ptr 呢?似乎使用Base*或Base&会简化这种情况,并且无需处理任何类型的智能指针。 -
@TheUndeadFish 你说得对,事实上界面过去看起来是这样的,我只是决定是时候拥抱 C++11 并且可能有点过分热情了。
标签: c++ pointers c++11 smart-pointers