静态变量在.dll / .lib中显示不同的行为

时间:2018-07-22 14:16:20

标签: c++ visual-c++ dll

我试图了解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;
}

enter image description here

0 个答案:

没有答案