C++;导致泄漏/未定义行为/崩溃的切片 有没有C++对象切片效果的例子,它会在一组正确的代码中造成不明确的行为、内存泄漏或崩溃?例如,当类A和B(继承自A)正确且可靠时,调用void f(A)显然会导致令人讨厌的事情
它是形成试题所必需的。我们的目标是使用一个示例代码片段来了解参与者是否意识到切片现象,该示例代码片段的正确性不能是一个意见问题。您始终可以构建这样一个示例C++;导致泄漏/未定义行为/崩溃的切片 有没有C++对象切片效果的例子,它会在一组正确的代码中造成不明确的行为、内存泄漏或崩溃?例如,当类A和B(继承自A)正确且可靠时,调用void f(A)显然会导致令人讨厌的事情,c++,object-slicing,C++,Object Slicing,它是形成试题所必需的。我们的目标是使用一个示例代码片段来了解参与者是否意识到切片现象,该示例代码片段的正确性不能是一个意见问题。您始终可以构建这样一个示例 struct A { A() : invariant(true) {} virtual void do_sth() { assert(invariant); } protected: bool invariant; }; struct B : A { B() { invariant=false; } virtual vo
struct A {
A() : invariant(true) {}
virtual void do_sth() { assert(invariant); }
protected:
bool invariant;
};
struct B : A {
B() { invariant=false; }
virtual void do_sth() { }
};
void f(A a)
{
a.do_sth();
}
当然,在A
中,当复制构造函数/赋值操作符不检查variator是否为true时,可以防止这种情况发生
如果不变量比我的布尔值更隐式,那么这些东西可能很难看到。您总是可以构造这样一个示例
struct A {
A() : invariant(true) {}
virtual void do_sth() { assert(invariant); }
protected:
bool invariant;
};
struct B : A {
B() { invariant=false; }
virtual void do_sth() { }
};
void f(A a)
{
a.do_sth();
}
当然,在A
中,当复制构造函数/赋值操作符不检查variator是否为true时,可以防止这种情况发生
如果不变量比我的布尔值更隐式,那么这些东西可能很难看到。如果
A
确实是“正确且可靠的”,那么切片(复制基本子对象)是定义良好的,不会导致您提到的任何问题。如果您希望副本的行为类似于B
,那么它将导致的唯一问题是意外行为
如果
A
不可正确复制,则切片将导致复制该类型的对象时出现任何问题。例如,如果它有一个析构函数,该析构函数删除对象所持有的指针,并且复制会创建指向同一对象的新指针,那么当两个析构函数删除同一指针时,您将获得未定义的行为。这不是切片本身的问题,而是切片对象的复制语义无效。如果a
确实“正确且可靠”,那么切片(复制基本子对象)定义良好,不会导致您提到的任何问题。如果您希望副本的行为类似于B
,那么它将导致的唯一问题是意外行为
如果
A
不可正确复制,则切片将导致复制该类型的对象时出现任何问题。例如,如果它有一个析构函数,该析构函数删除对象所持有的指针,并且复制会创建指向同一对象的新指针,那么当两个析构函数删除同一指针时,您将获得未定义的行为。这不是切片本身的问题,而是切片对象的无效复制语义的问题。只有通过指向派生类基类的指针或引用操作派生类时,对象切片才是真正的问题。然后,派生类的附加数据保持不变,而基础部分中的数据可能会被更改。这可能会破坏派生类的不变量。有关简单示例,请参见
但是,我会认为这是一个强的设计缺陷< /强>(派生类)。如果通过任何合法方法访问一个类,包括那些指向基类的指针或引用参数,都会破坏它的不变量,那么这个类的设计就很糟糕。避免这种情况的一种方法是将基
声明为private
,这样派生类就不能通过其基合法访问
例如:
class A
{
int X;
A(int x) : X(x) {}
void doubleX() { X+=X; }
/* ... */
};
class B : public A
{
int X_square;
B(int x) : A(x), X_square(x*x) {}
/* ... */
};
B b(3);
B.doubleX(); /// B.X = 6 but B.X_square=9
从本例中还可以明显看出,这是B中的一个简单设计缺陷
void B::doubleX() { A::doubleX(); X_squared=X*X; }
也不能解决问题
A&a=b;
a.doubleX();
仍然会破坏不变量。这里唯一的解决方案是将基
A
声明为私有,或者更好地说,使A
成为B
的私有成员,而不是基,只有通过指向其基类的指针或引用操作派生类时,对象切片才是真正的问题。然后,派生类的附加数据保持不变,而基础部分中的数据可能会被更改。这可能会破坏派生类的不变量。有关简单示例,请参见
但是,我会认为这是一个强的设计缺陷< /强>(派生类)。如果通过任何合法方法访问一个类,包括那些指向基类的指针或引用参数,都会破坏它的不变量,那么这个类的设计就很糟糕。避免这种情况的一种方法是将基
声明为private
,这样派生类就不能通过其基合法访问
例如:
class A
{
int X;
A(int x) : X(x) {}
void doubleX() { X+=X; }
/* ... */
};
class B : public A
{
int X_square;
B(int x) : A(x), X_square(x*x) {}
/* ... */
};
B b(3);
B.doubleX(); /// B.X = 6 but B.X_square=9
从本例中还可以明显看出,这是B中的一个简单设计缺陷
void B::doubleX() { A::doubleX(); X_squared=X*X; }
也不能解决问题
A&a=b;
a.doubleX();
仍然会破坏不变量。这里唯一的解决方案是将基
A
声明为私有,或者更好地说,使A
成为B
的私有成员,而不是基,我看不到任何未定义的行为1这不是对象切片,因为B
没有要切片的新数据。2我看不出你的代码有什么问题,除非你用一个B
参数调用f(A)
。@Walter:用B
参数调用f(A)
正是问题产生的地方:B
被分割成A
,然后在A::do_sth
中的断言失败。我没有看到任何未定义的行为1这不是对象切片,因为B
没有要切片的新数据。2我看不出你的代码有什么问题,除非你用一个B
参数调用f(A)
。@Walter:用B
参数调用f(A)
正是问题产生的地方:B
被分割成A
,然后在A::dou sth
中的断言失败。好的。有没有关于测试某人意识的提示?好的。那么关于测试某人的意识有什么提示吗?