3

In ContainerTest.h I have the following singleton class defined:

    class ContainerTest
    {
    private:
        ContainerTest()
        {
            test = InitializeTest();
        }

        ContainerTest(const ContainerTest&) = delete;
        ContainerTest(ContainerTest&&) = delete;
        ContainerTest& operator=(const ContainerTest&) = delete;
        ContainerTest& operator=(ContainerTest&&) = delete;
    public:
        std::vector<uint32_t> test;

        static ContainerTest& GetInstance()
        {
            static ContainerTest rhc;
            return rhc;
        }
    };

I am confused about whether only one instance of ContainerTest will exist throughout my program.

I.e., if two cpp files A.cpp and B.cpp both include ContainerTest.h will there be one instance of ContainerTest created, or two instances? Can someone explain this? And if there's two instances created (one for A and B's translation unit) how can I prevent this?

Bob Dole
  • 33
  • 2
  • 2
    There will be only one instance. ```static ContainerTest rhc``` will be shared throughout a single executable. – Steve May 30 '18 at 16:59
  • @Steve Thanks, is there any good resource that will let me brush up on translation unit rules for C++? I'm also assuming if GetInstance is not inlined by the compiler it will exist in only one place in memory? – Bob Dole May 30 '18 at 17:01
  • Can't find a really good straight to the point answer, but see this: https://stackoverflow.com/a/246568/425871 – Steve May 30 '18 at 17:04

1 Answers1

3

The static variable in the function will get a unique symbol name that is used by the linker to ensure there is only a single instance. It will generate a so called weak symbol, which may occur in multiple translation units. The Linker then will use only one instance. This will even work, when embedded in a dynamic library/shared object.

I used the following small test program: (mostly your code)

#include <vector>
#include <cstdint>



class ContainerTest
{
private:
    ContainerTest()
    { }

    ContainerTest(const ContainerTest&) = delete;
    ContainerTest(ContainerTest&&) = delete;
    ContainerTest& operator=(const ContainerTest&) = delete;
    ContainerTest& operator=(ContainerTest&&) = delete;
public:
    std::vector<uint32_t> test;

    static ContainerTest& GetInstance()
    {
        static ContainerTest rhc;
        return rhc;
    }
};


int main(int, char**)
{
    ContainerTest& ct = ContainerTest::GetInstance();
}

and compiled with gcc then I called:

nm -a libContainerTestSingleton.so |grep rhc| c++filt

Which provides the following output:

0000000000000000 b .bss._ZGVZN13ContainerTest11GetInstanceEvE3rhc
0000000000000000 b .bss._ZZN13ContainerTest11GetInstanceEvE3rhc
0000000000000000 u guard variable for ContainerTest::GetInstance()::rhc
0000000000000000 u ContainerTest::GetInstance()::rhc

A symbol, than is marked with an u means following: (nm manpage)

"u" The symbol is a unique global symbol.  This is a GNU extension to the
    standard set of ELF symbol bindings.  For such a symbol the dynamic 
    linker will make sure that in the entire process there is just one
    symbolwith this name and type in use.
kiloalphaindia
  • 561
  • 3
  • 7