jot*_*tik 25 c++ arrays inheritance terminology pointer-arithmetic
比方说,我有一个类Derived
从类派生Base
而sizeof(Derived) > sizeof(Base)
.现在,如果分配一个这样的数组Derived
:
Base * myArray = new Derived[42];
Run Code Online (Sandbox Code Playgroud)
然后尝试使用访问n
-th对象
doSomethingWithBase(myArray[n]);
Run Code Online (Sandbox Code Playgroud)
然后,由于Base
从无效位置访问,这可能(但不总是)导致未定义的行为.
这种编程错误的正确术语是什么?它应该被视为对象切片的情况吗?
Joh*_*nck 26
它根本不是切片,而是未定义的行为,因为你正在访问一个Derived
不存在的对象(除非你很幸运并且大小排成一行,在这种情况下它仍然是UB,但无论如何都可以做一些有用的事情).
这是一个失败的指针算法的简单案例.
jxh*_*jxh 19
如上所述,索引myArray
不会导致对象切片,但会导致索引到数组中导致的未定义行为,Derived
就好像它是一个数组一样Base
.
在分配中引入的缺陷new Derived[42]
,以myArray
可以是的变化阵列衰变错误.
在这种类型的bug的真实例子中,有一个实际的数组:
Derived x[42];
Base *myArray = x;
Run Code Online (Sandbox Code Playgroud)
之所以引入这个问题,是因为一个数组Derived
衰减成指针,Derived
其值等于其第一个元素的地址.衰减允许指针分配正常工作.此衰减行为继承自C,这是一种语言设计功能,允许数组"通过引用传递".
这导致我们更糟糕地体现了这个bug.此功能为数组语法提供C和C++语义,将数组函数参数转换为指针参数的别名.
void foo (Base base_array[42]) {
//...
}
Derived d[42];
foo(d); // Boom.
Run Code Online (Sandbox Code Playgroud)
但是,new[]
实际上是一个重载运算符,它返回指向已分配数组对象开头的指针.所以它不是数组衰减的真实实例(即使使用了数组分配器).但是,bug的症状是一样的,目的new[]
是得到一个数组Derived
.
通过使用智能指针对象而不是管理原始指针,可以避免这种问题.例如,类似的编码错误unique_ptr
看起来像:
std::unique_ptr<Base[]> myArray = new Derived[42];
Run Code Online (Sandbox Code Playgroud)
这会产生编译时错误,因为unique_ptr
s构造函数是explicit
std::reference
.或者,您可以避免使用new[]
和使用std::vector<Derived>
.然后,你会强迫自己设计一个不同的解决方案,将这个数组发送到只能Base
识别的框架代码.可能是模板功能.
void my_framework_code (Base &object) {
//...
}
template <typename DERIVED>
void my_interface(std::vector<DERIVED> &v) {
for (...) {
my_framework_code(v[i]);
}
}
Run Code Online (Sandbox Code Playgroud)
或者,通过使用std::reference_wrapper<Base>
.
std::vector<Derived> v(42);
std::vector<std::reference_wrapper<Base>> myArray(v.begin(), v.end());
Run Code Online (Sandbox Code Playgroud)
n. *_* m. 11
这不是任何方式的对象切片.
对象切片完全由C++标准定义.它可能违反了面向对象的设计原则或其他任何原则,但它并不违反C++规则.
此代码违反了5.7 [expr.add]第7段:
对于加法或减法,如果表达式
P
或Q
类型为"指向cv的 指针T
",其中T
与cv-unqualified数组元素类型不同,则行为未定义.[注意:特别是,当数组包含派生类类型的对象时,指向基类的指针不能用于指针算术. - 注意].
数组下标运算符被定义为等效于指针运算,5.2.1 [expr.sub]第1段:
表达式
E1[E2]
(根据定义)相同*((E1)+(E2))
归档时间: |
|
查看次数: |
1391 次 |
最近记录: |