`
RednaxelaFX
  • 浏览: 3047862 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

确定性析构在有指针的环境下的麻烦之处

    博客分类:
  • C++
阅读更多
刚考完大软,心里还在郁闷,随便发点牢骚吧……

昨天同学考C++的时候还有一题,是找出程序错误的题。代码大概是这样:
class A {
    int i;
};

class B {
    A* p;
public:
    B() { p = new A; }
    ~B() { delete p; }
};

void foo(B b) {
    // ...
}

int main() {
    B b;
    foo(b);
}

你看出问题在什么地方了么?

============================================================================

其实应该挺明显的,但昨天被同学问到的时候我却没能一眼看出来。郁闷啊。
foo()的参数是将B复制传递过去的。于是foo()里的参数b在离开foo()的作用域时会被析构,里面的成员p指向的A实例就一起被析构了。然后在main()里的b在离开main()时析构就会尝试再次delete掉同一个A的实例,引发错误。

So what am I trying to say? 这普通的C++毫无疑问是有确定性析构的——局部变量在离开其作用域时就会被析构;显式使用delete时也可以完成析构。正是因为这样,无意中造成的浅拷贝会让引起一些意想不到的问题,就像上面的代码那样。
为了应对这些问题,我们才有了烦琐的idioms,例如:
1、delete之前先检查指针是否为null;(然而不小心用错delete与delete[]运算符的话还是很糟糕)
2、尽量不对复合类型对象直接使用值传递给参数——可以用引用传递,也可以传指针,以减少复制(但如果不想让参数的值被改变怎么办呢?我们有const修饰符,也有拷贝构造函数和operator =的重载……自己实现深拷贝吧)
3、为了避免内存泄漏,我们可以采用RAII……呃
……

具有RAII的可能性是好是坏我觉得还可以一议,像C#或者Java就没办法用RAII,有些人也会说很不爽什么的。但是内存管理到底是应该留给程序员做还是应该让运行时解决掉,这毫无疑问是取决于程序所在的层次:高层的应用应该尽量避免涉及这些细节,一方面不容易出错,另一方面也减轻了程序员的负担。不然我们就得记下一堆idioms,多到能出一整系列的几本书来描述的量,才能写出正确的程序了……

以上纯属吐槽 =v=
C++是门好语言(嗯
分享到:
评论
6 楼 RednaxelaFX 2008-05-19  
顺带一提……这几天连续的都是考试,我从上个星期三到昨天没有一天是没有考试的;今天一直到后天还继续。所以上网时间没保证撒……T T
5 楼 RednaxelaFX 2008-05-19  
C++里,一个类的对象实例默认是可以被复制的,复制会在:
(1)以复制来初始化时:
SomeClass c = someInstance; // initialization by copy

(2)以复制来赋值时:
someInstance = someOtherInstance; // copy by assignment

默认提供的复制机制是将源对象里的每个成员都原封不动的复制到目标对象中;形象点说就是把源对象的每一bit都直接搬到目标对象上。这种复制方式也被称为浅拷贝(shallow copy)。
但我们不总是想允许这种浅拷贝,因为会带来潜在的安全问题(见上面)。当需要提供与默认复制机制不一样的行为时,我们可以
对(1):提供拷贝构造函数;
对(2):提供operator =的重载。
class SomeClass {
    // ...
    SomeClass( const SomeClass& ); // copy constructor
    operator =( const SomeClass& ); // copy assignment
};

另外,当我们希望禁止对象的复制时,可以提供私有的拷贝构造函数和operator =的重载。

可以参考The C++ Programming Language, 3rd Edition的10.2.5 Copying Class Objects [class.default.copy]和10.4.4.1 Copying Objects [class.copy]。
我在几天前发的一篇日记里写的那个Set的例子里也有拷贝构造函数和operator =重载的例子,对这个概念不熟悉的话可以看看。

不过明大肯定对这种概念比我熟悉多了,再怎么说平时写的C++代码都比我多多了,我懒啊不想用C++……
4 楼 Lighting 2008-05-17  
=  =!

貌似是叫拷贝构造函数吧~~~

PS:FX大长期不在啊……
3 楼 Lighting 2008-05-16  
啊……晕了……手残了!~!打少了关键的字了……

这样在foo调用结构后析构的b跟main里面的b是同的对象了……

应该是

这样在foo调用结构后析构的b跟main里面的b是不同的对象了……


(为啥没得编辑功能…… =_,= )
2 楼 Lighting 2008-05-16  
哦呀……像lwwin说的那样按引用传递的话的确是没问题~~~

看到这帖,刚开始我也很郁闷~~把b对象以参数形式传进去不会导致B的构造调用么,反汇编看结果才发现,原来只是进行简单的赋值操作而已……然后再写个B的构造
B(const B &obj)
{
     p=new A;
}
有这个构造的话在进行
B b;
foo(b)的时候,进入foo作用域后就会执行B(const B &obj)构造了~~~这样在foo调用结构后析构的b跟main里面的b是同的对象了……

其实我也觉得很奇怪,为啥有B(const B &obj)在的时候才会进行构造,没它在的话只是进行简单的赋值……
等FX大的解释!!!
1 楼 lwwin 2008-05-16  
void foo(B& b) {...} ???

相关推荐

    C++对象在堆栈区的析构

    在堆栈上,由于析构的自动性,程序员必须确保析构函数能够正确处理这些资源。否则,可能会导致内存泄漏或其他资源未释放的问题。 例如,如果`MyClass`有一个指向动态分配内存的指针: ```cpp class MyClass { ...

    构造析构的顺序

    正确处理构造和析构的顺序能避免资源泄露、悬挂指针等问题,保证程序的稳定性和可靠性。在实际编程中,我们应该遵循这些规则,合理设计类的结构,确保每个对象在生命周期的开始和结束都能得到正确的处理。

    c++句柄,智能指针 指针间的区别

    智能指针类将指针变量作为成员变量封装起来,在智能指针类对象离开作用域时,会再析构的过程中完成指针的释放。例如,使用auto_ptr智能指针类,可以自动释放所指向的对象内存,避免了手动delete的麻烦。 句柄、智能...

    200款鼠标指针库-鼠标指针设置-鼠标指针方案.zip

    这些个性化的指针可能有各种各样的主题,如卡通人物、动物形象、电影元素等,使用户在使用电脑时能感受到与众不同的视觉效果。 "鼠标指针方案"则是一系列配套的指针样式,包括不同操作状态下的指针,如待机、繁忙、...

    电脑设置鼠标指针更换仙剑奇侠传四鼠标指针

    在电脑上个性化自己的操作系统是许多用户喜欢做的事情,其中之一就是更换鼠标指针。本文将详细讲解如何在Windows系统中更改鼠标指针,以“仙剑奇侠传四”为主题的鼠标指针为例,为仙剑迷们提供一个独特的电脑体验。 ...

    【C语言】两个指针的坑

    指针在使用不当的情况下非常容易出现问题,尤其是内存越界、野指针(未初始化或者已经释放的指针)、空指针访问等,都会造成程序的运行时错误,甚至导致程序崩溃(core dump)。以下从给出的内容中提取知识点并详细...

    智能指针的一个实现 中科大 面向对象课程

    计数指针的实现通常涉及到原子操作(atomic operations),以确保在多线程环境下引用计数的更新是线程安全的。这通常通过C++的`std::atomic`库来实现,保证了在并发环境下引用计数的增加和减少不会出现数据竞争问题...

    Windows XP鼠标指针

    总的来说,自定义鼠标指针不仅能够增添系统个性化元素,还能提高用户的工作效率,因为某些特殊形状的指针可以在特定的操作环境下提供更好的视觉提示。在Windows XP中,通过简单的几步设置,用户就能享受到定制鼠标...

    智能指针错误用法demo

    但如果在智能指针作用域内提前手动释放资源(例如,调用`delete`),则智能指针在析构时会再次尝试释放,造成双释放错误。 5. **循环引用问题**: 当两个或多个`std::shared_ptr`相互引用时,它们的引用计数不会降...

    指针的艺术(纯类文件)

    这时,可以将指针作为类的成员变量,但需要注意的是,如果类的实例拥有指向动态分配对象的指针,那么在类的构造函数和析构函数中需要处理相应的内存管理。 5. **指针与函数参数**:在函数中,我们经常使用指针来...

    构造析构顺序.rar

    在C++编程语言中,构造函数和析构函数是类对象生命周期的重要组成部分。...在实际编程中,我们还需要注意异常安全性和避免悬垂指针等问题,这通常涉及到正确的构造和析构顺序以及适当的异常处理策略。

    win版mac电脑鼠标指针组合包

    因此,更换鼠标指针不仅要考虑视觉效果,也要确保新指针在不同场景下的可识别性,以便用户能够正确理解其功能。 在Windows系统中,除了预设的指针样式外,还有许多第三方开发者创建了各种各样的鼠标指针主题包供...

    windows-荧光鼠标指针

    荧光鼠标指针是一种特别设计的Windows环境下的鼠标指针样式,它采用了荧光效果,使得鼠标在屏幕上更加醒目,特别是在夜间或者低光照环境下,能够提高用户的操作体验和视觉舒适度。荧光颜色通常包括亮绿、亮蓝、亮黄...

    智能指针与引用计数详解

    5. 检查智能指针在不同情况下的行为,例如在所有智能指针都销毁后,对象是否正确释放。 总之,智能指针与引用计数是C++中管理动态内存的重要工具,通过理解和掌握这些知识,程序员可以编写出更加安全、高效的代码。...

    联想官方蓝色水晶鼠标指针

    1. 可见性:指针必须在任何背景下清晰可见。联想的蓝色水晶设计选择了一个对比度高的颜色,确保了即使在复杂背景上也能轻松追踪指针位置。 2. 美学:美观的指针设计能提升用户体验。蓝色水晶风格赋予了指针一种时尚...

    鼠标指针方案(如反转、黑色、特大)

    标题提及的“鼠标指针方案”包括反转、黑色以及特大等类型,这些都是为了满足不同用户在不同环境下的需求。 首先,我们来探讨一下反转指针方案。反转方案主要是针对那些在白色背景下工作或娱乐的用户,他们在寻找一...

    vista Aero鼠标指针

    不过,需要注意的是,为了兼容性和稳定性,确保在安装自定义鼠标指针前关闭所有正在运行的应用程序,并确保这些指针文件与你的操作系统版本兼容。 总的来说,"Vista Aero鼠标指针"提供了一种改变Windows Vista用户...

    Obsidian小黑鼠标指针

    例如,一些用户可能会选择高对比度的指针样式以提高在特定背景下的可见性,而"Obsidian小黑"鼠标指针则为喜欢低调风格的用户提供了一个不错的选择。 值得注意的是,虽然Windows系统提供了更改鼠标指针的功能,但并...

    windows10鼠标指针样式4种

    在Windows 10上启用此主题后,鼠标指针将会呈现出半透明和高光的效果,使得指针在各种颜色背景下都能保持良好的可见性。 2. **crystal clear**:顾名思义,这个主题可能主打的是清晰度和纯净感。它可能设计得非常...

    西门子之如何计算ANY型指针的偏移量或改变指针?.pdf

    4. 指针验证:在修改ANY型指针之后,应进行适当的验证,以确保指针指向了正确的数据对象,同时保证数据的完整性和程序的稳定性。 5. 使用SFC20块:SFC20是一个系统功能块,允许从一个数据块(DB)向另一个数据块(DB)...

Global site tag (gtag.js) - Google Analytics