在 MyClass 指针的容器中找到一个 void 指针?
Find a void pointer in an container of MyClass pointers?
我有一个指向未知类型变量的指针 void* p
,以及一个填充了 MyClass
指针的容器 std::set<MyClass*> c
。有没有办法找出 c
是否包含 p
(即它是否包含指向与 p
相同的内存地址的指针),而无需手动循环遍历 [=13] 中的元素=],这不会导致未定义的行为? (请注意,如果我在 c
中找不到它,我不会取消引用 p
。)
此外,我假设如果 p
指向一个不相关但与 [=12= 相关的数据类型的变量,则将 p
转换为 MyClass*
会导致未定义的行为],但也许并非如此?
您可以将 void*
安全地转换为另一个指针,但不应取消引用它。在 std::set<T*>
中查找指针不会取消引用指针(除非您指定一个自定义比较谓词)。
迂腐地,C++ 标准说仅仅加载一个无效的指针是未定义的行为。但是,这是针对具有 segmented addressing(x86 实模式)的硬件架构的规定,其中加载指针会将其值的一部分加载到段寄存器中,这可能会导致硬件陷阱。在具有平面内存模型的现代体系结构中,此限制不适用,加载任何指针值都是明确定义的,因为这只是加载到通用 CPU 寄存器中。
类似于:
MyClass* find(std::set<MyClass*> const& c, void* p) {
auto found = c.find(static_cast<MyClass*>(p));
return found != c.end() ? *found : nullptr;
}
您可以像这样使用它:
std::set<MyClass*> c;
void* p = ...;
if(MyClass* q = find(c, p))
// p is found and is q
在实践中,您应该能够做到(参见其他答案和评论),但您需要注意一些陷阱。
如果您有 class 派生自另一个 class(比如 OtherClass
)和 MyClass
,那么您需要确保 p
指向MyClass
部分而不是 OtherClass
。虽然您不会有未定义的行为,但您不会找到该项目。
class OtherClass { int someData; };
class WontWork : public OtherClass, public MyClass { };
auto *w = new WontWork();
c.insert(w);
void *p = w;
在这种情况下,您不会在集合中找到 p
,因为 p
的值与插入集合中的值不同(在隐式转换为 MyClass *
之后).
要使代码正常工作,您需要 p
指向 MyClass
部分,方法如下:
void *p = static_cast<MyClass *>(w);
或
MyClass *mc = w;
p = mc;
但是,您必须确保在代码的其他地方不使用 p
,就好像它是 OtherClass
或 WontWork
类型一样。
如果可能,最好通过修复声明来完全避免void *
。
I assume that casting p
to MyClass*
would cause undefined behavior if [..]
它可能会导致 UB 是迂腐的正确。
但在实践中可能会奏效(UB 的乐趣)。
Is there some way to find out whether c contains p [..] without manually looping through the elements in c.
std::find_if
或 std::binary_search
可以与适当的谓词一起使用以在线性时间内找到它(std::set::iterator
不是随机迭代器,因此 "falsify" binary_search
复杂度)。
如果您可以将容器更改为:
std::set<MyClass*, std::less<void>>
,那么你可以安全地使用std::set::find
感谢透明比较器。
排序 std::vector<MyClass*>
,那么您可以使用具有正确复杂度的 std::binary_search
。
我有一个指向未知类型变量的指针 void* p
,以及一个填充了 MyClass
指针的容器 std::set<MyClass*> c
。有没有办法找出 c
是否包含 p
(即它是否包含指向与 p
相同的内存地址的指针),而无需手动循环遍历 [=13] 中的元素=],这不会导致未定义的行为? (请注意,如果我在 c
中找不到它,我不会取消引用 p
。)
此外,我假设如果 p
指向一个不相关但与 [=12= 相关的数据类型的变量,则将 p
转换为 MyClass*
会导致未定义的行为],但也许并非如此?
您可以将 void*
安全地转换为另一个指针,但不应取消引用它。在 std::set<T*>
中查找指针不会取消引用指针(除非您指定一个自定义比较谓词)。
迂腐地,C++ 标准说仅仅加载一个无效的指针是未定义的行为。但是,这是针对具有 segmented addressing(x86 实模式)的硬件架构的规定,其中加载指针会将其值的一部分加载到段寄存器中,这可能会导致硬件陷阱。在具有平面内存模型的现代体系结构中,此限制不适用,加载任何指针值都是明确定义的,因为这只是加载到通用 CPU 寄存器中。
类似于:
MyClass* find(std::set<MyClass*> const& c, void* p) {
auto found = c.find(static_cast<MyClass*>(p));
return found != c.end() ? *found : nullptr;
}
您可以像这样使用它:
std::set<MyClass*> c;
void* p = ...;
if(MyClass* q = find(c, p))
// p is found and is q
在实践中,您应该能够做到(参见其他答案和评论),但您需要注意一些陷阱。
如果您有 class 派生自另一个 class(比如 OtherClass
)和 MyClass
,那么您需要确保 p
指向MyClass
部分而不是 OtherClass
。虽然您不会有未定义的行为,但您不会找到该项目。
class OtherClass { int someData; };
class WontWork : public OtherClass, public MyClass { };
auto *w = new WontWork();
c.insert(w);
void *p = w;
在这种情况下,您不会在集合中找到 p
,因为 p
的值与插入集合中的值不同(在隐式转换为 MyClass *
之后).
要使代码正常工作,您需要 p
指向 MyClass
部分,方法如下:
void *p = static_cast<MyClass *>(w);
或
MyClass *mc = w;
p = mc;
但是,您必须确保在代码的其他地方不使用 p
,就好像它是 OtherClass
或 WontWork
类型一样。
如果可能,最好通过修复声明来完全避免void *
。
I assume that casting
p
toMyClass*
would cause undefined behavior if [..]
它可能会导致 UB 是迂腐的正确。
但在实践中可能会奏效(UB 的乐趣)。
Is there some way to find out whether c contains p [..] without manually looping through the elements in c.
std::find_if
或 std::binary_search
可以与适当的谓词一起使用以在线性时间内找到它(std::set::iterator
不是随机迭代器,因此 "falsify" binary_search
复杂度)。
如果您可以将容器更改为:
std::set<MyClass*, std::less<void>>
,那么你可以安全地使用std::set::find
感谢透明比较器。排序
std::vector<MyClass*>
,那么您可以使用具有正确复杂度的std::binary_search
。