首页 > 其他分享 >静态库中单例不唯一的情况

静态库中单例不唯一的情况

时间:2024-01-27 15:13:24浏览次数:33  
标签:单例 静态 libB libA libC 库中 cpp MeyerSingleton testlibheader1

提出问题

A作为共享库,封装了一个单例类,共享库B和共享库C使用A,D作为可执行程序,使用B和C,那么这个单例是否唯一?

实验

首先创建一个C++项目,项目结构如下

.
├── CMakeLists.txt
├── MeyerSingleton.cpp
├── MeyerSingleton.h
├── testlib.cpp
├── testlibheader1.cpp
├── testlibheader1.h
├── testlibheader2.cpp
└── testlibheader2.h

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 17)

project(test)

// libA
add_library(libA SHARED MeyerSingleton.h MeyerSingleton.cpp)

//libB
add_library(libB SHARED testlibheader1.h testlibheader1.cpp)
target_link_libraries(libB libA)

//libC
add_library(libC SHARED testlibheader2.h testlibheader2.cpp)
target_link_libraries(libC libA)

//exeD
add_executable(testABC testlib.cpp)
target_link_libraries(testABC libB libC)
MeyerSingleton.h
#ifndef MEYER_SINGLETON_H
#define MEYER_SINGLETON_H
class MeyerSingleton
{
private:
    MeyerSingleton();
    ~MeyerSingleton();
    MeyerSingleton(const MeyerSingleton&);
    MeyerSingleton& operator=(const MeyerSingleton&);
public:
    static MeyerSingleton& getInstance();
};
#endif

MeyerSingleton.cpp

#include <iostream>
#include "MeyerSingleton.h"

MeyerSingleton &MeyerSingleton::getInstance()
{
    static MeyerSingleton instance;
    return instance;
}

MeyerSingleton::MeyerSingleton(){
    std::cout<<"MeyerSingleton initialized!"<<std::endl;
}
MeyerSingleton::~MeyerSingleton(){
    std::cout<<"MeyerSingleton destroyed!"<<std::endl;
}

testlibheader1和testlibheader2定义了一个函数来调用这个单例,如下
testlibheader1.h

#ifndef TESTLIB_HEADERS_1_H
#define TESTLIB_HEADERS_1_H
namespace tb1{
    void test();
}
#endif
testlibheader1.cpp
#include <iostream>
#include <thread>
#include <sstream>
#include "testlibheader2.h"
#include "MeyerSingleton.h"
namespace tb2{
    void test(){
        std::string msg;
        std::stringstream sin;
        sin << &MeyerSingleton::getInstance();
        sin >> msg;
        std::cout << msg << std::endl;
    }
}

再在可执行程序中使用这俩个库文件

#include "testlibheader1.h"
#include "testlibheader2.h"

int main(int argc, char **argv){
    tb1::test();
    tb2::test();
    return 0;
}

编译运行结果如下:

MeyerSingleton initialized!
0x1051b8000
0x1051b8000
MeyerSingleton destroyed!

运行结果看起来一切正常。
如果把libA作为静态库呢?于是对CMakeLists.txt作出修改

project(test)

// libA
add_library(libA MeyerSingleton.h MeyerSingleton.cpp) //设定libA为静态库

//libB
add_library(libB SHARED testlibheader1.h testlibheader1.cpp)
target_link_libraries(libB libA)

//libC
add_library(libC SHARED testlibheader2.h testlibheader2.cpp)
target_link_libraries(libC libA)

//exeD
add_executable(testABC testlib.cpp)
target_link_libraries(testABC libB libC)

再次编译运行,结果如下:

MeyerSingleton initialized!
0x1027ec000
MeyerSingleton initialized!
0x102800000
MeyerSingleton destroyed!
MeyerSingleton destroyed!

可以看到,libA中的单例类MeyerSingleton初始化了两次,并且通过libB和libC获取到的单例不是同一个。
接下来将libA中MeyerSingleton::getInstance移动到函数内部

#ifndef MEYER_SINGLETON_H
#define MEYER_SINGLETON_H
class MeyerSingleton
{
private:
    MeyerSingleton();
    ~MeyerSingleton();
    MeyerSingleton(const MeyerSingleton&);
    MeyerSingleton& operator=(const MeyerSingleton&);
public:
    static MeyerSingleton& getInstance()
    {
        static MeyerSingleton instance;
        return instance;
    }
};
#endif

再次运行,结果如下

MeyerSingleton initialized!
0x100cac000
0x100cac000
MeyerSingleton destroyed!

看起来问题解决了,再把libA设为动态库后运行结果如下:

MeyerSingleton initialized!
0x10430c000
0x10430c000
MeyerSingleton destroyed!

结论

由此能够得到一个结论,libA作为静态库被libB和libC调用时单例地址可能不一致,经过测试有如下情形:

  • 当libA作为静态库且在cpp文件中实现getInstance时,libB和libC同时作为动态库时出现这个问题
  • 当libA作为动态库时,libB和libC作为动态库或者静态库时都没有这个问题
    所以为了避免这个问题,最好的方式是,将getInstance的实现内联在.h文件中

标签:单例,静态,libB,libA,libC,库中,cpp,MeyerSingleton,testlibheader1
From: https://www.cnblogs.com/pengpengda/p/17991448

相关文章

  • `pandas.ExcelFile.parse` 和 `pandas.read_excel` 都是 pandas 库中用于从 Excel 文
    `pandas.ExcelFile.parse`和`pandas.read_excel`都是pandas库中用于从Excel文件读取数据并创建DataFrame的方法¹。这两个方法的主要区别在于它们的使用场景和语法。-`pandas.read_excel`是一个函数,它可以直接读取Excel文件并返回一个DataFrame¹。这个函数非常适合......
  • C++ 单例模式
    单例模式写法:注意:静态成员使用指针的话,程序退出时无法指针类的析构函数,在类内添加回收单例的类,析构的时候将该单例对象析构,就可以了例如:classSingleton{public: staticSingleton*getInstance() { if(m_pInstance==nullptr)//静态成员使用指......
  • Blazor Hybrid应用将非wwwroot目录下的文件加入静态资源
    以Winfrom为例,创建一个Class继承BlazorWebView这个类,重写CreateFileProvider这个方法就行。保存后,用新控件替换原来的控件,WPF,MAUI同理,但是MAUI只有Windows平台能用下面的代码。其他平台会报错,找不到文件。publicclassCustomBlazorWebView:BlazorWebView{......
  • STA(静态时序分析) 详解:如何计算最大时钟频率,以及判断电路是否出现时钟违例(timing viola
    1.什么是STA?     STA(静态时序分析)是时序验证的一种方法,用于计算和分析电路是否满足时序约束的要求。 2.为什么需要STA?    电路能否正常工作,其本质上是受最长逻辑通路(即关键路径)的限制,以及受芯片中存储器件的物理约束或工作环境的影响。    为了保......
  • 45从零开始用Rust编写nginx,静态文件服务器竟然还有这些细节
    wmproxywmproxy已用Rust实现http/https代理,socks5代理,websocket代理,反向代理,静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透等,力争打造和nginx的性能。项目地址国内:https://gitee.com/tickbh/wmproxygithub:https://github.com/tickbh/wmproxy静态文件服务器静态......
  • 29虚函数-静态绑定-动态绑定
    虚函数-静态绑定-动态绑定如果类中定义了虚函数,那么编译阶段,编译器会给这个类类型产生一个唯一的vftable虚函数表,其中主要存储的是RTTI指针和虚函数的地址。程序运行时,每一张虚函数表都会加载到内存的.rodata只读数据区。一个类中定义了虚函数,那么这个类的对象,其运行时,内存中开......
  • 静态路由基本配置
    拓扑:配置:查看代码[R1]discurrent-configuration[V200R003C00]#sysnameR1#boardadd0/12SA#snmp-agentlocal-engineid800007DB03000000000000snmp-agent#clocktimezoneChina-Standard-Timeminus08:00:00#portallocal-serverloadportalpage.......
  • 静态区间查询(条件动态)——ST表
    目录问题引入思路一览具体分析条件动态?问题引入给出一个长度为n的数组a,并且给出m咨询问,每次询问给出边间lt和rt,要求给出lt和rt之间的最大值思路一览暴力法:记录数组,对于每一次询问,就从lt到rt遍历一遍ST:对数组的区间做一个倍增处理,将每一个区间的答案记录下来,最后使用区间进行......
  • 内部类(匿名、成员、静态)
    1、匿名内部类匿名内部类在方法中创建,不能用public等来修饰在方法内部使用,此时,只需要声明一个Outer05对象,然后使用f1方法,就可以使用这个匿名内部类 类的匿名内部类,如果去掉大括号中的内容,则变成创建一个Father对象,但是有这个大括号,则是使用一个匿名内部类,如果类本身不是......
  • Linux-unbuntu里静态库、动态库
    静态库:特点:生成的可执行程序复制了一份整个库,以空间换取时间第一步:准备功能函数eg:add.c sub.c  div.c...第二步:把功能函数只编译不链接,得到.o文件gcc-cadd.c-oadd.o第三步:将功能函数的.o文件进行打包成库(打包完成会生成一个.a结尾的库,此库里已经把功能函数都封装进来了)ar......