C++--智能指针、逻辑操作符的陷阱

一.智能指针

内存泄漏(C++主要的Bug来源)
1.动态申请堆空间,用完后不归还
2.C++语言中没有垃圾回收机制
3.指针无法控制所指堆空间的生命周期
代码示例

#include <iostream>
#include <string>

using namespace std;

class Test
{
    int i;
public:
    Test(int i)
    {
        this->i = i;
    }
    int value()
    {
        return i;
    }
    ~Test()
    {
    }
};

int main()
{
    for(int i=0; i<5; i++)
    {
        Test* p = new Test(i);

        cout << p->value() << endl;
    }

    return 0;
}

运行的结果如图所示

可以看出输出结果如预期一样,但是指针在申请了内存之后没有进行释放,但当出现大量的数据时,程序会崩溃
智能指针的需求与目的
1.需要一个特殊的指针
2.指针生命周期结束时主动释放堆空间
3.一片堆空间最多只能有一个指针标识
4.杜绝指针运算何指针比较
解决方案
1.重载指针特征操作符(->)
2.只能通过类的成员函数重载
3.重载函数不能使用参数
4.只能定义一个重载函数
代码示例

#include <iostream>
#include <string>
//智能指针的实现
using namespace std;

class Test
{
    int i;
public:
    Test(int i)
    {
        cout << "Test(int i)" << endl;
        this->i = i;
    }
    int value()
    {
        return i;
    }
    ~Test()
    {
        cout << "~Test()" << endl;
    }
};

class Pointer
{
    Test* mp;
public:
    Pointer(Test* p = NULL)
    {
        mp = p;
    }
    Pointer(const Pointer& obj)
    {
        mp = obj.mp;
        const_cast<Pointer&>(obj).mp = NULL;
    }
    Pointer& operator = (const Pointer& obj)
    {
        if( this != &obj )
        {
            delete mp;
            mp = obj.mp;
            const_cast<Pointer&>(obj).mp = NULL;
        }

        return *this;
    }
    Test* operator -> ()
    {
        return mp;
    }
    Test& operator * ()
    {
        return *mp;
    }
    bool isNull()
    {
        return (mp == NULL);
    }
    ~Pointer()
    {
        delete mp;
    }
};

int main()
{
    Pointer p1 = new Test(0);

    cout << p1->value() << endl;

    Pointer p2 = p1;

    cout << p1.isNull() << endl;

    cout << p2->value() << endl;

    return 0;
}

运行的结果如图所示

可以看到,指针在在对堆空间使用完之后,会自动释放内存
小结
1.指针特征操作符可以被重载
2.重载指针特征符能够使用对象代替指针
3.智能指针只能用于指向堆空间中的内存
4.智能指针的意义在于最大程度的避免内存问题

二.逻辑操作符的陷阱

A.逻辑运算符的原生语义
1.操作数只有两种值(true与false)
2.逻辑表达式不用完全计算就能确定最终值
3.最终结果只能是true或者false
代码示例

#include <iostream>
#include <string>

using namespace std;

int func(int i)
{
    cout << "int func(int i) : i = " << i << endl;

    return i;
}

int main()
{
    if( func(0) && func(1) )
    {
        cout << "Result is true!" << endl;
    }
    else
    {
        cout << "Result is false!" << endl;
    }

    cout << endl;

    if( func(0) || func(1) )
    {
        cout << "Result is true!" << endl;
    }
    else
    {
        cout << "Result is false!" << endl;
    }

    return 0;
}


Q:逻辑操作符可以重载吗?重载逻辑操作符有什么意义?
代码示例及结果

#include <iostream>
#include <string>

using namespace std;

class Test
{
    int mValue;
public:
    Test(int v)
    {
        mValue = v;
    }
    int value() const
    {
        return mValue;
    }
};

bool operator && (const Test& l, const Test& r)
{
    return l.value() && r.value();
}

bool operator || (const Test& l, const Test& r)
{
    return l.value() || r.value();
}

Test func(Test i)
{
    cout << "Test func(Test i) : i.value() = " << i.value() << endl;

    return i;
}

int main()
{
    Test t0(0);
    Test t1(1);

    if( func(t0) && func(t1) )
    {
        cout << "Result is true!" << endl;
    }
    else
    {
        cout << "Result is false!" << endl;
    }

    cout << endl;

    if( func(1) || func(0) )
    {
        cout << "Result is true!" << endl;
    }
    else
    {
        cout << "Result is false!" << endl;
    }

    return 0;
}


可以从代码及运行结果可以看出,无论逻辑操作符是否更换两端顺序,都会对两端数据进行运算
B.问题的本质分析
1.C++通过函数调用扩展操作符功能
2.进入函数体前必须完成所有参数的计算
3.函数参数的计算次序是不定的
4.短路法则完全失效
建议:实际工程开发中避免重载逻辑操作符,通过重载比较操作符代逻辑操作符重载,直接使用成员函数代替逻辑操作符重载,使用全局函数对逻辑操作符重载
小结
1.C++从语法上支持逻辑操作符重载
2.重载后的逻辑操作符不满足短路法则
3.工程开发中不要重载逻辑操作符
4.通过重载比较操作符替换逻辑操作符重载
5.通过专用成员函数替换逻辑操作符重载

原文地址:https://blog.51cto.com/13475106/2412496

时间: 2024-11-05 19:05:09

C++--智能指针、逻辑操作符的陷阱的相关文章

智能指针的使用与陷阱

在包含指针的类中需要注意复制控制,复制指针时只复制指针中的地址,不会复制指针指向的对象. 大多数c++类采用三种方法管理指针成员: 1)指针成员采用常规指针型行为. 2)采用智能指针 3)采取值型行为 常规指针缺陷:可能会出现悬垂指针.当一个指针复制到另一个指针,两个指针指向同一个对象,当一个指针删除对象时,另一个指针不知道,所以出现悬垂指针.即使使用默认合成复制构造函数也会出现,类本身无法避免. 智能指针:加入了引用计数.引用计数跟踪该类有多少对象共享同一指针.当引用计数为0 时,删除对象.创

第38课 逻辑操作符的陷阱

1. 逻辑运算符的原生语义 (1)操作数只有两种值(true和false) (2)逻辑表达式不用完全计算就能确定最终值 (3)最终结果只能是true或false [编程实验]逻辑表达式 #include <iostream> using namespace std; int func(int i) { cout << "int func(int i): i = " << i << endl; return i; } int main()

逻辑操作符的陷阱

逻辑运算符的原生语义 操作数只有两种值(true和false) 逻辑表达式不用完全计算就能确定最终值 最终结果只能是true或者false 那么,如果我们重载逻辑运算符会发生什么? 例: 1 #include <iostream> 2 #include <string> 3 using namespace std; 4 class Test 5 { 6 int value; 7 public: 8 Test(int _value) 9 { 10 this->value = _

OSG 智能指针陷阱

先看下这个代码,有什么问题: #include <osg/Group> #include <osg/Node> #include <osg/Geode> osg::Geode *geode= NULL; osg::ref_ptr<osg::Group> root = NULL; void createNode(){ geode = new osg::Geode; geode->setName("Hello"); root = new

智能指针陷阱

1.不使用相同的内置指针初始化多个智能指针(reset也不行) 2.不delete get() 返回的指针 3.不使用gat() 初始化 或reset 其他智能指针 4.如果使用get()返回的指针,要记住当最后一个智能指针被销毁后,指针就变得无效了. 5.if使用的智能指针管理的资源不是new分配的,要传给他们一个删除器

Boost智能指针-基础篇

简介 内存管理一直是 C++ 一个比较繁琐的问题,而智能指针却可以很好的解决这个问题,在初始化时就已经预定了删除,排解了后顾之忧.1998年修订的第一版C++标准只提供了一种智能指针:std::auto_ptr(现以废弃),它基本上就像是个普通的指针:通过地址来访问一个动态分配的对象.std::auto_ptr之所以被看作是智能指针,是因为它会在析构的时候调用delete操作符来自动释放所包含的对象.当然这要求在初始化的时候,传给它一个由new操作符返回的对象的地址.既然std::auto_pt

【C++】C++问题——类模板分离编译、函数对象、智能指针

C++类模板的分离编译 过去很多类模板都是整个类连同实现都放在一个头文件里,像STL库就是遵循这样的策略来实现类模板的.现在的标准正试图矫正这种局面. 在实现中又许多函数模板.这意味着每个函数都必须包含模板声明,并且在使用作用域操作符的时候,类的名称必须通过模板变量来实例化. 比如一个operator=的代码: template <typename Object> const MemoryCell <Object> & MemoryCell<Object>::o

C++11中智能指针的原理、使用、实现

目录 理解智能指针的原理 智能指针的使用 智能指针的设计和实现 1.智能指针的作用 C++程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理.程序员自己管理堆内存可以提高了程序的效率,但是整体来说堆内存的管理是麻烦的,C++11中引入了智能指针的概念,方便管理堆内存.使用普通指针,容易造成堆内存泄露(忘记释放),二次释放,程序发生异常时内存泄露等问题等,使用智能指针能更好的管理堆内存. 理解智能指针需要从下面三个层次: 从较浅的层面看,智能指针是利用了一种叫做RAII(资

boost智能指针之shared_ptr和weak_ptr

std::auto_ptr很多的时候并不能满足我们的要求,比如auto_ptr不能用作STL容器的元素.boost的smart_ptr中提供了4种智能指针和2种智能指针数组来作为std::auto_ptr的补充. shared_ptr<boost/shared_ptr.hpp>:使用shared_ptr进行对象的生存期自动管理,使得分享资源所有权变得有效且安全. weak_ptr<boost/weak_ptr.hpp>:weak_ptr 是 shared_ptr 的观察员.它不会干