简体   繁体   English

跨编译单元的单例:链接库与链接对象

[英]Singleton across compilation units: linking library vs linking objects

I apologize if the title is not fully self-explanatory. 如果标题不完整,我深表歉意。 I'm trying to understand why my singleton factory pattern is not working properly, and I ran into a bizarre difference when using library vs linking single objects files. 我试图理解为什么我的单例工厂模式无法正常工作,并且在使用库与链接单个对象文件时遇到了一个奇怪的区别。

Here's a simplified version of the code: 这是代码的简化版本:

main.cpp main.cpp

#include <iostream>
#include "bar.hpp"

int main (int /*argc*/, char** /*argv*/)
{
  A::get().print();
  return 0;
}

bar.hpp bar.hpp

#ifndef BAR_HPP
#define BAR_HPP

#include <iostream>

class A
{
public:
  static A& get ()
  {
    static A a;
    return a;
  }
  bool set(const int i)
  {
    m_i = i;
    print();
    return true;
  }
  void print ()
  {
    std::cout << "print: " << m_i << "\n";
  }
private:

  int m_i;
  A () : m_i(0) {}
};
#endif // BAR_HPP

baz.hpp baz.hpp

#ifndef BAZ_HPP
#define BAZ_HPP

#include "bar.hpp"

namespace
{
static bool check = A::get().set(2);
}

#endif // BAZ_HPP

baz.cpp baz.cpp

#include "baz.hpp"

Now, I build my "project" in two ways: 现在,我以两种方式构建“项目”:

Makefile: 生成文件:

all:
  g++ -std=c++11 -c baz.cpp
  g++ -std=c++11 -o test main.cpp baz.o
lib:
  g++ -std=c++11 -c baz.cpp
  ar rvs mylib.a baz.o
  g++ -std=c++11 -o test main.cpp mylib.a

Here are the outputs I get: 这是我得到的输出:

$ make all
$ ./test
print: 2
print: 2

$ make lib
$ ./test
print: 0

In the first case the call to A::get().set(2) in baz.hpp takes place, and the same instantiation of A is then used in the main function, which therefore prints 2 . 在第一种情况下,对baz.hpp中的A::get().set(2)进行了调用,然后在主函数中使用了A的相同实例,因此输出2 In the second case, the call to A::get().set(2) in baz.hpp never takes place, and in the main function the value set by the constructor (that is, 0 ) is printed. 在第二种情况下,永远不会发生对baz.hpp中的A::get().set(2)的调用,并且在主函数中,将打印由构造函数设置的值(即0 )。

So finally I can ask my question: why is the behavior different in the two cases? 所以最后我可以提出一个问题:为什么两种情况下的行为不同? I would expect that either both print 0 once or print 2 twice. 我希望两个都打印一次或两次打印两次。 I always assumed that a library was just a compact way to ship object files, and that the behavior of linking mylib.a should be the same as that of linking baz.o directly. 我一直以为库只是一种运送目标文件的紧凑方式,并且链接mylib.a的行为应与直接链接baz.o的行为相同。 Why isn't that the case? 为什么不这样呢?

Edit: the reason, as explained by Richard, is that no symbols defined in baz.cpp are required in main.cpp, so baz.o is not extracted from the library and linked. 编辑:正如Richard所解释的,原因是main.cpp中不需要在baz.cpp中定义的符号,因此baz.o不会从库中提取并链接。 This raises another question: is there a workaround to ensure that the instruction A::get().set(2) is executed? 这就提出了另一个问题:是否有解决方法来确保执行指令A::get().set(2) I would like to avoid making the singleton a global object, but I'm not sure it's possible. 我想避免使单例成为全局对象,但我不确定是否有可能。 I would also like to avoid to include baz.hpp in the main, since there may be many bazxyz.hpp and that would require main.cpp to know in advance all of them, defying the whole purpose of the factory-like registration process... 我还想避免在主程序中包含baz.hpp,因为可能有很多bazxyz.hpp ,这将要求main.cpp事先知道所有这些,而无视工厂式注册过程的整个目的。 ..

If this is to be a static library, then some module somewhere is going to have to address something in each implementation file of the objects that are going to register themselves with the factory. 如果这是一个静态库,那么某个模块将必须在对象的每个实现文件中处理要在工厂注册的对象。

A reasonable place for this would be in bar.cpp (which is a file you don't yet have). 一个合理的位置将在bar.cpp (这是您还没有的文件)中。 It would contain some or all of the implementation of A plus some means of calling the registration functions the widgets you're going to create. 这将包含以下部分或全部的实施A加致电登记功能,你要创建的小部件的一些手段。

Self-discovery only works if the object files are linked into the executable. 仅当目标文件链接到可执行文件时,自我发现才起作用。 This gives the c++ startup sequence a chance to know about and construct all objects with global linkage. 这使c ++启动序列有机会了解和构造具有全局链接的所有对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM