将 std 库函数专门用于用户定义类型的shared_ptr是否合法?
Is it legal to specialize std library functions for a shared_ptr of a user defined type?
该标准对标准库中的专用模板有以下说明(通过我可以和不能专注于 std 命名空间?
程序可以添加模板 仅将任何标准库模板专用化为命名空间 std 如果声明依赖于用户定义类型,并且 专业化满足标准库要求 原始模板,未明确禁止。
使用专用于用户定义类的标准库类来专门化标准库模板是否合法?
例如,专门针对std::shared_ptr<MyType>
std::hash
?
从阅读上述段落和链接问题来看,听起来应该是,因为专业化的声明取决于MyType
,但是"除非明确禁止"让我有点担心。
下面的示例按预期编译和工作(AppleClang 7.3),但它合法吗?
#include <unordered_set>
#include <memory>
#include <cassert>
#include <string>
struct MyType {
MyType(std::string id) : id(id) {}
std::string id;
};
namespace std {
template<>
struct hash<shared_ptr<MyType>> {
size_t operator()(shared_ptr<MyType> const& mine) const {
return hash<string>()(mine->id);
}
};
template<>
struct equal_to<shared_ptr<MyType>> {
bool operator()(shared_ptr<MyType> const& lhs, shared_ptr<MyType> const& rhs ) const {
return lhs->id == rhs->id;
}
};
}
int main() {
std::unordered_set<std::shared_ptr<MyType>> mySet;
auto resultA = mySet.emplace(std::make_shared<MyType>("A"));
auto resultB = mySet.emplace(std::make_shared<MyType>("B"));
auto resultA2 = mySet.emplace(std::make_shared<MyType>("A"));
assert(resultA.second);
assert(resultB.second);
assert(!resultA2.second);
}
是的,这是合法的。
在某一时刻专门从事std::shared_ptr<int>
甚至值得怀疑;我不知道他们是否将标准中的歧义修补为缺陷。
请注意,这是全局使用的哈希值的糟糕实现。 首先,因为它不支持空共享指针。 其次,因为像往常一样散列共享指针的 int 值是有问题的。 这甚至是危险的,因为如果指向容器中 int 的共享指针具有该 int 更改,那么您只是破坏了程序。
考虑为这类情况制作自己的哈希器。
namespace notstd {
template<class T, class=void>
struct hasher_impl:std::hash<T>{};
namespace adl_helper {
template<class T>
std::size_t hash( T const& t, ... ) {
return ::notstd::hasher_impl<T>{}(t);
}
};
namespace adl_helper2 {
template<class T>
std::size_t hash_helper(T const& t) {
using ::notstd::adl_helper::hash;
return hash(t);
}
}
template<class T>
std::size_t hash(T const& t) {
return ::notstd::adl_helper2::hash_helper(t);
}
struct hasher {
template<class T>
std::size_t operator()(T const& t)const {
return hash(t);
}
};
}
现在,这允许 3 点自定义。
首先,如果覆盖包含T
的命名空间中的std::size_t hash(T const&)
,它会选取它。
如果做不到这一点,如果你专门为你的T
型notstd::hasher_impl<T, void>
,它会拾取它。
第三,如果两者都失败了,它就会调用std::hash<T>
,选择任何专业。
然后你可以做:
std::unordered_set<std::shared_ptr<MyType>, ::notstd::hasher> mySet;
并添加:
struct MyType {
MyType(std::string id) : id(id) {}
std::string id;
friend std::size_t hash( MyType const& self) {
return ::notstd::hash(self.id);
}
friend std::size_t hash( std::shared_ptr<MyType> const& self) {
if (!self) return 0;
return ::notstd::hash(*self);
}
};
这应该给你一个聪明的哈希值shared_ptr<MyType>
.
这保留了有人在shared_ptr<MyType>
上更改id
的危险,从而以非本地方式破坏包含shared_ptr<MyType>
的每个容器。
共享状态是魔鬼;如果你真的担心复制这些东西很昂贵,请考虑在写入指针上写一个副本。
- CLANG 编译器 说:变量"PTR"可能未初始化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 在调用函数时,ptr** 和 ptr*& 之间是否有区别,或者首选C++?
- 另一种类型的智能ptr,比如具有弱refs的unique_ptr
- 尝试打印出 *ptr++ 的值,以了解它是如何工作的
- 如何控制共享 ptr 引用计数?
- dopen():不以 root 身份运行时"failed to map segment from shared object"
- C++中的指针否定 (!ptr == NULL)
- 从const ptr*转换为ptr*时出现问题
- 无法使用 libtool 将 -shared 参数传递给 g++
- boost::shared_ptr和std::shared-ptr的同居
- 我可以用std::shared_ptr而不是boost::shared-ptr构建boost库吗
- shared-ptr-C++shared_ptr与unique_ptr用于资源管理