我试图了解dll / lib中静态方法的工作原理,所以我进行了以下测试:
创建三个项目:
1) libadd //has an class Object and a template class Single<T>
2) libuseadd //has a function useadd which will call
// Single<Object>::instance in libadd
3) app // main() will call
// Single<Object>::instance in libadd and
// useadd in libuseadd
// =========== libadd =====================
//add.h
#pragma once
#include <iostream>
class __declspec(dllexport) Object
{
public:
Object():cnt_(0){}
void speak()
{
std::cout<<"object:"<<cnt_++<<std::endl;
}
private:
int cnt_;
};
template<typename T>
class __declspec(dllexport) Single
{
public:
static T& instance()
{
static T t;
return t;
}
};
//add.cpp
#include "add.h"
// CMakelists.txt
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
set(PORJ_NAME libadd)
project(${PORJ_NAME})
add_library(${PORJ_NAME}
add.h
add.cpp
)
// =========== libuseadd =====================
//useadd.h
#pragma once
__declspec(dllexport) void useadd();
//useadd.cpp
#include "useadd.h"
#include "add.h"
void useadd()
{
Object& obj = Single<Object>::instance();
obj.speak();
}
// CMakeLists.txt
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
set(PORJ_NAME libuseadd)
project(${PORJ_NAME})
add_library(${PORJ_NAME}
useadd.h
useadd.cpp
)
target_include_directories( ${PORJ_NAME}
PRIVATE
add/
PUBLIC
)
target_link_libraries (${PORJ_NAME}
PRIVATE
bin/libadd.lib
)
// ==================== main.cpp ========================
#include "add.h"
#include "useadd.h"
int main(int argc, char* argv[])
{
Object& obj1 = Single<Object>::instance();
obj1.speak();
useadd();
return 0;
}
// CMakelists.txt
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
set(PORJ_NAME app)
project(${PORJ_NAME})
add_executable(${PORJ_NAME}
main.cpp
)
target_include_directories( ${PORJ_NAME}
PRIVATE
add
useadd
PUBLIC
)
target_link_libraries (${PORJ_NAME}
PRIVATE
libadd.lib
libuseadd.lib
)
如果结果是:
object:0
object:1
那么这意味着instance()函数内部的静态变量只有一个实例(正确)。
如果结果是:
object:0
object:0
这意味着instance()函数内部的静态变量是重复(错误!)
我发现结果取决于该库是编译为dll还是lib。 当libadd和libuseadd全部都编译为dll时,它甚至取决于实例函数在.h还是cpp中的实现。假设我们必须将add.h / add.cpp更改为:
//when libadd/libuseadd all are dll, we have to use the codes below to
//make it work correctly.
template<typename T>
class __declspec(dllexport) Single
{
public:
static T& instance();
};
template class Single<Object>;
//add.cpp
#include "add.h"
#include "add.h"
template<typename T>
T& Single<T>::instance()
{
static T t;
return t;
}
http://127.0.0.1:8000/any/thing/here/bluebook/
我想知道为什么
已更新(删除模板和类Object):
// =========== libadd =====================
//add.h
#pragma once
#include <iostream>
class __declspec(dllexport) Single
{
public:
static int& instance()
{
static int t = 0;
int tmp = t++;
return tmp;
}
};
//add.cpp
#include "add.h"
// =========== libuseadd =====================
//useadd.h
#pragma once
__declspec(dllexport) void useadd();
//useadd.cpp
#include "useadd.h"
#include "add.h"
#include <iostream>
using namespace std;
void useadd()
{
cout<< Single::instance() <<endl;
}
// =========== main.cpp ======================
//main.cpp
#include "add.h"
#include "useadd.h"
using namespace std;
int main(int argc, char* argv[])
{
cout << Single::instance() << endl;
useadd();
return 0;
}