В шаблоне синглтона, что делает экземпляр уникальным? - PullRequest
0 голосов
/ 24 апреля 2019

На практике одиночный шаблон создается с помощью простой статической функции, которая возвращает одну локальную статическую переменную.Пока экземпляр является статическим, он возвращает одну и ту же переменную, определенную один раз во время первого вызова функции.

Меня сбивает с толку то, что если я объявляю обычную статическую функцию со статической локальной переменной в одном файле заголовка и включаю этот заголовок в два разных блока перевода, когда они вызывают эту функцию, локальная статическая переменная функции создается дважды -каждый для каждой единицы перевода.

Причина в том, что при статическом идентификаторе функции функция связывания является внутренней, поэтому для каждой единицы перевода (исходного файла) существует два экземпляра этих функций, и, следовательно, для этой статической переменной есть два локальных экземпляра.

Мой вопрос: почему эта же логика не применима к одноэлементному шаблону?Когда мы объявляем статическую функцию, почему она не внутренне связана и, следовательно, почему она не создает два экземпляра локальной статической переменной (которая по определению является единственным экземпляром синглтона)?

основная функция синглтона, о которой я говорюо:

static className& instance() { static className instance; return instance; }

Ответы [ 2 ]

1 голос
/ 24 апреля 2019

Потому что static [dcl.stc] / 4 не всегда означает внутреннюю связь.При применении к обычной функции области пространства имен, такой как

static void fun();  // fun has internal linkage

спецификатор static, объявляет эту функцию внутренней связью [basic.link] / 5 .Это главным образом для обратной совместимости с C. В C ++ вам лучше использовать безымянное пространство имен для объявления сущностей с внутренней связью, чтобы избежать именно той путаницы, которая приводит к вашему вопросу:

namespace
{
    void fun();  // fun has internal linkage, C++ style
}

При применении к функции-члену класса спецификатор static объявляет, что функция является static функцией-членом этого класса, т. Е. Функцией, которая не работает с экземплярамиэтого класса, но это просто обычная функция, объявленная в области действия этого класса, например:

class X
{
public:
    static void fun();  // fun is a static member function with external linkage
};

void test()
{
    X::fun();  // invoke fun
}

Связывание с функцией, не являющейся областью пространства имен, такой как статическая функция-член, не затрагивается ключевым словомstatic.В результате вышеприведенная статическая функция-член будет иметь внешнюю связь [basic.link] / 6 .

Помимо всего этого: шаблон Singleton почти наверняка не будет правильнымВыбор того, что вы хотите сделать. Не делай этого.

0 голосов
/ 24 апреля 2019

Функция, которая возвращает синглтон , не должна быть статической, только сам синглтон.

Это было бы неправильно

//header file - bad implementation of singleton pattern

class foo {/*stuff*/};

static foo& getFoo() {
    static foo myFoo;
    return myFoo;
}

Эта реализация привела бы кразные myFoo возвращаются в каждой единице компиляции, поскольку каждая единица компиляции имеет свою собственную getFoo функцию

Что вы должны сделать так:

//header file - good implementation of singleton pattern

class foo {/*stuff*/};

foo& getFoo();

//source file - good implementation of singleton pattern

foo& getFoo() {
    static foo myFoo;
    return myFoo;
}

Теперь каждая единица компиляции будет ссылатьсята же самая функция getFoo и получение того же синглтона (поскольку функция не является статической)


В качестве тестируемого примера, демонстрирующего это.

//foo.h
#include <iostream>

static void print_num_times_called() {
    static int num_times_called = 0;
    ++num_times_called;
    std::cout << num_times_called << "\n";
}

void call_print_num_times_called();

//foo.cpp
#include "foo.h"

void call_print_num_times_called() {
    print_num_times_called();
}

//main.cpp
#include "foo.h"

void main() {
    for (int i = 0; i < 10; ++i) {
        print_num_times_called();
    }
    for (int i = 0; i < 10; ++i) {
        call_print_num_times_called();
    }
}

//output

1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...