对象切片或UB风险
Object slicing or UB risk?
有几个基类在我的控制之外,像这样:-
class BaseNode // Just a POD class. No VTable
{
void foo();
}
class BaseHost
{
public:
BaseNode *getNode()
{
...
}
}
我想"扩展"BaseNode::foo
的功能,但是类是有效密封的。
建议如下:-
class MyNode: public BaseNode
{
void foo()
{
// do my stuff..., then
BaseNode::foo();
}
}
class MyHost: public BaseHost
{
public:
MyNode *getNode()
{
return (MyNode*) BaseHost::getNode(); // Slicing or UB risk?
}
}
如果MyNode
引入额外的类成员或虚拟方法,事情将会变得严重错误-但如果满足这些约束,我仍然有UB吗?
还有其他问题吗?还是我需要重新考虑整个设计?
这种下拉法使用时要格外小心:它很容易导致UB。
标准保证您可以安全地从MyNode*
转换为BaseNode*
:
4.10/3:类型为"指向cv D的指针"的右值,其中D为类类型,可转换为类型为"指向cv B的指针"的右值,其中B是d的基类,如果B是不可访问的或有歧义的基类对于D,需要这种转换的程序是病态的。的的基类子对象的指针派生类对象。空指针值被转换为目的类型的空指针值。
但是让我们来玩火吧:标准还允许你在某些条件下从BaseNode*
施放到MyNode*
:
5.2.9/11:类型为"指向cv1 B的指针"的右值,其中B是类类型,可以转换为类型为"指向cv2 D的指针"的右值,其中D是从B派生的类,如果从的有效标准转换"指向D的指针"到"指向B的指针"存在,cv2也是一样cv-qualification等于或大于cv-qualification,且B是既不是D的虚基类,也不是D的虚基类的基类。空指针值被转换为空指针目的类型的值。如果"类型的右值指向"cv1 B"指向一个B,该B实际上是类型对象的子对象D,结果指针指向类型D的封闭对象。否则,行为是未定义的
我试着把这些引语翻译成纯文本:
- 如果您确定
BaseHost::getNode()
返回指向MyNode
对象的上行指针,并且在您的类层次结构中没有虚拟继承,那么就可以了。 - 但是如果
BaseHost::getNode()
会返回其他东西(例如指向普通BaseNode
或BaseNode
的另一个兄弟派生的指针),您将拥有UB。
BaseNode
类(例如,有一个虚拟析构函数),你可以使用一个更安全的dynamic_cast
。 相关文章:
- 'string.assign(string.data(), 5)' 是明确定义的还是 UB?
- 用C++中的std::condition_variable将线程置于死锁中会有风险吗
- 使用 CTRP 时,是否访问访问父构造函数 UB 中的子属性?
- 为什么我会收到此错误?无法将 {lb, ub} 从<大括号括起来的初始值设定项列表>转换为 float(**)(float*, int)
- 将空*参数转换为各种类型的参数是UB吗?
- 通过指针恢复对数组的引用.UB与否?
- 传递给放置 new 的指针是否是指向其对象表示形式的非 UB 指针?
- 使用 std::addressof(std::cout) 而不是 &std::cout 是否有任何风险?
- 如何在窗口之间移动 std::unique_ptr 而不会冒内存泄漏的风险?
- 在未初始化的变量上使用复合赋值运算符(+=, ..)不是C++中的UB?
- 使用lock_guard采用的互斥锁会导致 UB 吗?
- 模板与常规函数歧义 - UB?
- 在不释放所有动态分配的资源的情况下结束程序是否有风险
- 是否通过单元化指针UB访问静态类成员
- 是否可以默认使用UB
- QString::utf16(): Is it UB or not?
- 带有 QSharedMemory 的 IPC,如果其中一个进程挂起,则存在风险
- 创建自己的owner_ptr类;在传递堆栈或静态分配的地址时如何避免UB?
- 当原始数据是常量时,修改指针指向的位置是 UB 吗?
- 对象切片或UB风险