什么样的类不适宜用智能指针(Boolan)

我最不喜欢循规循矩,虽然是让写笔记,照着老师的ppt抄一遍有什么意思。所以我还是喜欢写自己的东西。

最近我有个怪癖,爱把所有带指针的类都改造成使用智能指针来控制资源分配和回收。因为我认为既然是c++11标准出的应该是可以顶替99标准,更安全更先进的用法,为什么不用呢?结果在这两周侯捷老师的c++课上的例子的智能指针改写上吃了苦头,也领悟到什么时候该用智能指针,什么时候不该用。离提交作业的日期只剩两天不到,有空的话我会将我对Date类,Rectangle类的改写也在这里讲一下。

我这里目的并不是讲解智能指针,所以讲的并不细。

什么是智能指针:

智能指针就是通过模板实现的对普通指针的一种封装,我偏爱用shared_ptr指针。通过引用计数,来管理自己的引用数量,当计数为0时,自动释放内存。

什么时候该用它呢?

本来我有个A类型的指针:

A *a = new A();

这样我还要操心去delete它。假如这行代码在一个函数内,并且a会作为该函数的返回值返回的话(比如第一周的作业Date类随机产生10个日期返回的函数)那选择什么时候delete就很重要了。有的时候不好抉择,增加维护的复杂程度。

那么这就是智能指针大显身手的时候。

shared_ptr<A> a = make_shared<A>();

起到了和刚才那条语句一样的效果。
假如这个函数是

shared_ptr<A> fun() {
  shared_ptr<A> a = make_shared<A>();
// 对a做点什么
 return a;
}

这样的话,函数里定义a,引用计数为1,返回a,a的引用计数仍为1.而当a使用完毕后,到了函数使用时所在作用域的结束位置时。a的引用计数会-1,此时为0,自动释放内存。不用我们人工delete了。

String类不使用shared的模样

这个String类是我自己写的,但跟课程里的只有一点点不一样。
返回成员的函数返回类型我设为const char*,因为这样的话可以避免使用函数时对成员做出我们不期望的修改。


#ifndef STRING_H
#define STRING_H

#include <cstring>
#include <iostream>
using std::ostream;

class String {
public:
    String(const char *cstr = 0);
    String(const String&);
    String &operator=(const String&);
    ~String();
    const char* get() const;
private:
    char *m_data;
};

inline
String::String(const char *cstr) {
    if (cstr) {
        m_data = new char[strlen(cstr) + 1];
        strcpy(m_data, cstr);
    } else {
        m_data = new char[1];
        *m_data = '\0';
    }
}

inline
String::String(const String &str) {
    m_data = new char[strlen(str.m_data) + 1];
    strcpy(m_data, str.m_data);
}

inline
String& String::operator=(const String &right) {
    if (this == &right) return *this;

    delete[] m_data;
    m_data = new char[strlen(right.m_data) + 1];
    strcpy(m_data, right.m_data);

    return *this;
}

inline
String::~String() {
    delete[] m_data;
}

inline
const char* String::get() const {  // 这里返回类型加了const
    return m_data;
}

inline
ostream& operator<<(ostream& os, const String& str) {
    // auto s = str.get();
    // strcpy(s, "h");
    return os << str.get();
}
#endif

这是使用后(惨不忍睹,跑不起来):

#ifndef STRING_H
#define STRING_H

#include <cstring>
#include <memory>
#include <iostream>
using std::ostream;
using std::shared_ptr;
using std::make_shared;

class String {
public:
    String(const char *cstr = 0);
    String(const String&);
    String &operator=(const String&);
    ~String();
    const char* get() const;
private:
    shared_ptr<char> m_data;
};

inline
String::String(const char *cstr) {
    char* pstr; 
    if (cstr) {
        pstr = new char[strlen(cstr) + 1];
        strcpy(pstr, cstr);
    } else {
        pstr = new char[1];
        pstr = '\0';
    }
    m_data = make_shared<char> (pstr, [](char *pstr){ delete[] pstr; });
}

inline
const char* String::get() const {
    return m_data.get();
}

inline
ostream& operator<<(ostream& os, const String& str) {
    return os << str.get();
}
#endif

这里可以明确的告诉大家,这段程序跑不起啦。但是这里可以看出智能指针的一个优点。那就是使用智能指针后,所有成员都不是指针类型,若没有特殊操作的话,拷贝构造,赋值运算符重载,析构,三大函数都可以只用默认的就可以,极大的减少了代码量。

但这个类并不适宜用智能指针。原因现在可能看不太出来。接下来我会将我对Date类的改写和Rectangle类的改写放出来。这样就比较清晰了。

Date类同理,也跑不起来,但我还是在这里把代码贴上

/*
 * 用于随机生成和排序的数组
 */
const int DATE_SIZE = 10;
/*
 * 生成10个随机日期
 */
unique_ptr<Date[]> CreatePoints() {
    unique_ptr<Date[]> dates(new Date[DATE_SIZE]);
    for (int i = 0; i < DATE_SIZE; ++i) {
        int year = rand() % 1000 + 1500;
        int month = rand() % 12 + 1;
 
        int maxDay = 28;
        switch (month) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                maxDay = 31;
                break;
            case 4:
            case 6:
            case 9:
            case 11:
                maxDay = 30;
                break;
            case 2:
                if ((year % 4 == 0 && year % 100 != 0)
                        || year % 400 == 0) 
                    maxDay = 29;
                break;
        }
        int day = rand() % maxDay + 1;
 
        dates[i] = Date(year, month, day);
    }
 
    return dates;
}
 
/*
 *    按从小到大的顺序排列日期数组
 */
unique_ptr<Date[]> Sort(unique_ptr<Date[]> &dates) {
    sort(&dates[0], &(dates[DATE_SIZE - 1]) + 1);
    return dates;
}

这两者的共同点就是需要改造成智能指针的都是数组,也就是说,如果数组之类对要绑定成智能指针的变量有依赖或顺序关系的情形下,使用智能指针并不明智,c++ primer书中也讲,尽量少用数组,多用标准库容器。而不得不用数组的情况下,还是使用new,delete管理或别的方式比较好。

而有的情形很适合智能指针,比如下面的Rectangle类:

class Shape {
    int no;
};

class Point {
    int x, y;
public:
    Point() = default;
    Point(const int &x = 0, const int &y = 0):x(x), y(y){}
};

class Rectangle: public Shape {
    int width, height;
    shared_ptr<Point> leftUp;
public:
    Rectangle(const int&, const int&, const int&, const int&);
    // 使用智能指针,拷贝,赋值,析构使用默认即可
};

inline
Rectangle::Rectangle(const int &w, const int &h, const int &x, const int &y):leftUp(make_shared<Point>(x, y)), width(w), height(h){}

这样成员只是单个对象的时候将其改为智能指针就很爽啦,Rectangle类的拷贝,赋值,析构全部省去,也不用有释放内存问题的担心。

这只是我这几天学习c++以来的想法,不一定正确,等以后功力深了说不定我自己都会推翻现在的想法。所以有什么疑问尽管在下面留言,希望我们的思想能碰撞出智慧的火光,共同进步。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容