C++ 在静态库的情况下,不会创建未引用的静态对象?

C++ 在静态库的情况下,不会创建未引用的静态对象?,c++,object,static,C++,Object,Static,开发环境GNU GCC(g++)4.1.2,CMAKE 当我读了一本权威的书《James Coplien的高级C++编程风格和成语》(我必须承认这本书很老,所以你们中的一些人可能发现它过时了),我发现“范例成语”很有损于继承类层次之间的相互依赖性。因此,我们尝试创建一个简单的项目来处理这个习语,如下所示 感谢您的耐心等待,我将整个源代码列在下面 在CMakeLists.txt中 cmake_minimum_required(VERSION 2.6) project(TestProject)

开发环境GNU GCC(g++)4.1.2,CMAKE

当我读了一本权威的书《James Coplien的高级C++编程风格和成语》(我必须承认这本书很老,所以你们中的一些人可能发现它过时了),我发现“范例成语”很有损于继承类层次之间的相互依赖性。因此,我们尝试创建一个简单的项目来处理这个习语,如下所示

感谢您的耐心等待,我将整个源代码列在下面

在CMakeLists.txt中

cmake_minimum_required(VERSION 2.6)

project(TestProject)

add_library(exemplar_idiom STATIC base.cpp derived1.cpp)

add_executable(exemplar_example main.cpp)
target_link_libraries(exemplar_example exemplar_idiom)
set_target_properties(exemplar_example PROPERTIES OUTPUT_NAME exemplar_example)
在examplar.h中

#ifndef EXEMPLAR_H_
#define EXEMPLAR_H_

class   Exemplar
{
public:
    Exemplar() {};
};

#else
#endif  //  EXEMPLAR_H_
在base.h中

#ifndef BASE_H_
#define BASE_H_

#include <string>

class   Exemplar;

class   Base
{
public:
    Base(Exemplar /* no use */);
    Base();

    virtual Base*   make(const std::string& key);

    virtual void    memberMethod1();
    virtual int     memberMethod2();

    virtual ~Base() {};
protected:
    static  Base*   list_;
    Base*   next_;

};

#else
#endif  //  BASE_H_
在derived1.cpp中

#include <iostream>

#include "exemplar.h"
#include "derived1.h"

static Exemplar exemplar;
static Derived1 derived1Exemplar(exemplar);

Derived1::Derived1(Exemplar a) : Base(a)
{
    std::cout << "Derived object exemplar ctor" << std::endl;
}

Derived1::Derived1() : Base() {}

Derived1*   Derived1::make(const std::string& key)
{
    Derived1* retval = 0;
    if (key == "derived1")
    {
        retval = new Derived1();
    }
    return retval;
}

void    Derived1::memberMethod1()
{
    std::cout << "Derived1::memberMethod1" << std::endl;
}

int    Derived1::memberMethod2()
{
    /*  dummy   */
    std::cout << "Derived1::memberMethod2" << std::endl;
    return 0;
}
当我们通过将“STATIC”关键字替换为“shared”来稍微更改CMakeLists.txt以创建共享对象时,我可以看到我预期的行为。我可以看到,由于Derived1类对象(带有examplar arg)的静态对象创建,基类中的链接列表链得到了正确维护。在那之后,当从main()中的base examplar对象调用virtual make()方法时,我可以看到通过指定键字符串“Derived1”和“base”成功创建了Derived1对象和base对象

但是,如果我将关键字“SHARED”还原为“STATIC”,那么我可以看到不同的结果。似乎根本没有创建这样的静态对象(Derived1示例对象)。因此,它无法通过调用make(“Derived1”)成员方法来创建Derived1对象

有没有办法避免这个问题,即使是在静态库的情况下?我希望静态对象构造函数对基类的链接列表产生副作用


我不确定我在这里想说的对你是否有意义。但是,如果您能给我上面的指针,我将不胜感激。

是的,GNU链接器
ld
只添加它认为实际使用的符号
ld
只能检查符号是否正在使用,但不能检查是否使用了符号初始化的副作用

因此,结果将是像您这样的情况,由于未初始化未使用的静态对象而导致失败

链接时,您可以使用
--whole archive
通知链接器包含所有符号。缺点是,您永远不想使用的符号也会被添加,并导致代码大小增加

另一件需要注意的事情是:


链接器仅当未使用的对象文件来自库时才会删除它们。明确传递给链接器的对象文件将始终被链接。

感谢您的明确回答。当我遵循上述观点并看到发生了什么时,我可以看到我所期望的正确行为。
#include "base.h"

#ifndef DERIVED1_H_
#define DERIVED1_H_

class   Exemplar;

class   Derived1 : public Base
{
public:
    Derived1(Exemplar /* no use */);

    //  Conventional default constructor which will be used to instantiate normal object
    Derived1();

    virtual Derived1*   make(const std::string& key);
    virtual void    memberMethod1();
    virtual int     memberMethod2();
};

#else
#endif  //  DERIVED1_H_
#include <iostream>

#include "exemplar.h"
#include "derived1.h"

static Exemplar exemplar;
static Derived1 derived1Exemplar(exemplar);

Derived1::Derived1(Exemplar a) : Base(a)
{
    std::cout << "Derived object exemplar ctor" << std::endl;
}

Derived1::Derived1() : Base() {}

Derived1*   Derived1::make(const std::string& key)
{
    Derived1* retval = 0;
    if (key == "derived1")
    {
        retval = new Derived1();
    }
    return retval;
}

void    Derived1::memberMethod1()
{
    std::cout << "Derived1::memberMethod1" << std::endl;
}

int    Derived1::memberMethod2()
{
    /*  dummy   */
    std::cout << "Derived1::memberMethod2" << std::endl;
    return 0;
}
#include "base.h"

extern Base* baseExemplar;

int main()
{
    Base *ptr = baseExemplar->make("derived1");
    if (ptr) {
        ptr->memberMethod1();
        ptr->memberMethod2();
    }

    Base *ptr2 = baseExemplar->make("base");
    if (ptr2) {
        ptr2->memberMethod1();
        ptr2->memberMethod2();
    }

    return 0;
}