关于C++实现单例模式的一些堆栈作用域的小问题

前几天晚上,给公司做机器人导航的舒少讲了几个常用的设计模式,主要是创建类型的工厂、建造者之类的。昨天晚上临下班他找我问了一个关于C++单例模式的一个问题。

问题是这同样的:
他看了一篇文章,里面实现了饿汉模式的单例,将构造函数私有化,提供公开静态的GetInstance()方法。这都毫无疑问,作者是这样写的代码。

#pragma once

class Singelton {
private:
    static Singelton *single;
    static Singelton single1;
    Singelton(){
        printf("Singelton create\n");
    }
public:
    static Singelton *GetSingelton();
    static void print();
};
#include <iostream>
using namespace std;

Singelton *Singelton::single = new  Singelton;
Singelton Singelton::single1 = Singelton();

void Singelton::print(){
    cout<<"123"<<endl;
}

Singelton *Singelton::GetSingelton(){
    return single;
}
#include <iostream>
using namespace std;

int main(int argc, const char * argv[]) { 
    Singelton * singelton =  Singelton::GetSingelton();
    singelton->print();
    return 0;
}

舒少的问题在这一行:

Singelton *Singelton::single = new  Singelton;
Singelton Singelton::single1 = Singelton();

明明构造函数已经私有化了,这里还明目张胆的调用~

折腾了一下:
问题答案是这样的,静态的公开变量,赋值的时候作用域是扩展到了后面的,整个赋值语句都在Singelton::的上下文中。

static Singelton *single;
static Singelton single1;

所以可以调用构造函数,而且不论是new还是不用new.

问题就这样解决了吗?
不是的,伴随而来的又产生了新的疑问:
内存有堆栈之分,使用静态创建的对象存在于栈中,而使用动态创建的对象放入堆中,静态的变量存放在单独的静态区。
如果我不想让一个变量放在栈中,自己进行内存管理,可以使用私有化析构函数的方法,因为使用静态创建对象的时候,系统会判断该对象的析构函数是否能够调用,如果不能调用就会导致创建失败。
不过如果使用动态创建的方式,即:

new  Singelton

那么这个对象的内存将创建在堆上,需要我们手动delete。

以上定义都没问题,反常识的是,当使用new进行创建对象的时候,系统会调用该对象的new操作,所以我们可以对这个操作进行重载:
像下面这个样子:

#pragma once

class Singelton {
private:
    static Singelton *single;
    static Singelton single1;
    Singelton(){
        printf("Singelton create\n");
    }
public:
    static Singelton *GetSingelton();
    static void print();
        void* operator new(size_t t){
        printf("operate new\n");
    } 
    void operator delete(void* ptr){
        printf("operate delete\n");
    } 
};

一起看起来没问题,运行!
然后你发现,结果是这个样子的:

operate new
Singelton create

这意味着,是先调用new,后调用构造函数的,那问题就是没调用构造函数之前,为什么可以调用它的成员函数new?还是说new这玩意算不上成员函数?
问题的答案大概是这样子:

  1. 此new 非彼new,真正的new应该是一系列操作,包括分配空间,创建对象,返回等一系列骚操作
  2. 既然系统可以在没有产生对象调用构造函数,那系统一定可以在没有创建之前调用new的操作符重载内容

所以说,这只是一种规则而已,理解即可,不必纠结~
具体可以看一下new的源码,应该会比价通透一些。

受到了传统思维限制了,认为没有对象就不能调用其非静态成员函数~~
好好学习,天天向上~
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值