Как использовать синглтон C ++ для возврата объекта, инициализированного только один раз

Я настоящий нубик C ++, поэтому, пожалуйста, будьте терпеливы со мной. Сначала давайте подготовим почву.

У меня есть источник C ++ в binary.cpp который компилируется в двоичный файл, который выглядит следующим образом:

# include "lotsofheaders.h"
int main(int argc, char* argv[])
{
int errorcode = FOOBAR_GLOBAL_UNKNOWN;

// foobar instanciation
Foobar foobar();

// multiple calls to :send_auth passing in foobar instance
errorcode = send_auth(getX(), getY(), foobar);
errorcode = send_auth(getX(), getY(), foobar);
errorcode = send_auth(getX(), getY(), foobar);

return errorcode == FOOBAR_OK ? EXIT_SUCCESS : EXIT_FAILURE;
}

send_auth Метод загружается из другого файла объектного кода, и ему передается экземпляр foobar. Причина в том, что Foobar происходит от объекта API, источником которого я не являюсь, и который НЕ ДОЛЖЕН быть создан более одного раза.

Поскольку main вызывается только один раз, все работает как положено: существует только один экземпляр Foobar и send_auth можно вызывать несколько раз.

Двоичный файл мне не нужен, мне нужна библиотека общих объектов, которая делает то же самое. Он создает только один экземпляр Foobar и предоставляет метод внешнего интерфейса. send_with_auth это может быть вызвано несколько раз после загрузки моего общего объекта lib.

Код моей библиотеки в library.cpp выглядит примерно так:

# include "lotsofheaders.h"# include "library.h"
const char* send_with_auth(const char* X, const char* Y){
std::string x(X);
std::string y(Y);

int result = send_auth(x, y, 'some Foobar singleton');

return true;
}

Так как я загружаю свою библиотеку общих объектов через Ruby FFI, мне нужны некоторые заголовки C-Style в library.h для моей библиотеки:

extern "C" {
const char* send_with_auth(const char* X, const char* Y);
}

Теперь со сценическим набором я должен создать экземпляр Foobar ровно один раз внутри моей библиотеки и передавать его в каждый вызов send_auth не получить ошибку нарушения памяти от Foobar.

Вот моя (слишком сложная) попытка синглтона, как я понял. Есть новый library.h вот так:

extern "C" {
class Singleton
{
private:
static bool instanceFlag;
static Singleton *single;
Singleton()
{
//private constructor
}
public:
static Foobar* fo;
static Singleton* getInstance();
~Singleton()
{
instanceFlag = false;
}
};
const char* send_with_auth(const char* X, const char* Y);
}

И есть эта реализация library.cpp:

# include "lotsofheaders.h"# include "library.h"
bool Singleton::instanceFlag = false;
Singleton* Singleton::single = NULL;
Singleton* Singleton::getInstance()
{
if(! instanceFlag)
{
single = new Singleton();
instanceFlag = true;
// bringing up my Foobar instance once and only once
Foobar fo;
single->fo = &fo;
return single;
}
else
{
return single;
}
}

const char* send_with_auth(const char* X, const char* Y){
std::string x(X);
std::string y(Y);

Singleton *single;
single = Singleton::getInstance();

int result = send_auth(x, y, *single->fo);

return true;
}

Этот код по крайней мере компилируется, и я могу связать все вместе с библиотекой общего объекта. Теперь, когда я загружаю эту библиотеку во внешний процесс (модуль Ruby с использованием Ruby FFI в моем случае), я всегда получаю ошибку:

Could not open library '/some/path/libfoobar.so': /some/path/libfoobar.so: undefined symbol: _ZN9Singleton2erE (LoadError)

Я совершенно уверен, что мой процесс компиляции / связывания / зачистки из library.o в libfoobar.so в порядке, потому что в других случаях это удается. Я совершенно уверен, что неправильно понял концепцию синглтона в C ++. Интересно, как я могу достичь своей цели: создать только один экземпляр Foobar внутри моей библиотеки общих объектов и передавать его при каждом вызове только тех методов, которые моя библиотека предоставляет извне.

Кто-нибудь может помочь с этим?
С уважением, Феликс

Использовать CommandlineParser в библиотеке было глупо. На самом деле он просто вернул две C-строки. Путь к библиотеке API и каталог журнала. С этим я воссоздал пространство имен:

namespace
{
char* home("/path/to/api/libs");
char* log("/tmp");
Foobar foobar(home, log);
}

Это приводит к ошибке сегмента в тот момент, когда я загружаю библиотеку. В отличие от этого я могу поместить эти строки в мою функцию напрямую:

const char* send_with_auth(const char* X, const char* Y){
std::string x(X);
std::string y(Y);

char* home("/path/to/api/libs");
char* log("/tmp");
Foobar foobar(home, log);

int result = send_auth(x, y, &foobar);

return true;
}

Здесь все отлично работает, кроме того, что второй звонок send_with_authпозволяет сбить все, потому что Foobar снова создается.

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

namespace baz{
bool foobarInitialized = false;
}

const char* send_with_auth(const char* certificatePath, const char* certificatePin, const char* xmlData){
std::string certificate_path(certificatePath);
std::string certificate_pin(certificatePin);
std::string xml_data(xmlData);

Foobar *foobar_ptr;

if (! baz::foobarInitialized) {
char* home_dir("/path/to/api/lib");
char* log_dir("/tmp");
foobar_ptr = new Foobar(home_dir, log_dir);
baz::foobarInitialized = true;
}

int result = send_auth(x, y, foobar_ptr);

return xml_data.c_str();
}

Теперь я могу позвонить send_with_auth бесконечно без создания Foobar более одного раза. Готово!

0

Решение

Итак, мое первое предложение — сделать

Самая простая вещь, которая могла бы работать

и избавиться от синглтона полностью. Просто создайте глобальный объект Foobar в вашей библиотеке:

// library.cpp
namespace {
Foobar global_foobar;
}

Я поместил его в анонимное пространство имен, чтобы он не конфликтовал с любым другим символом, называемым «global_foobar», в основном исполняемом файле или другой библиотеке.

Это означает, что к нему можно получить доступ только из library.cpp. Если у вас есть более одного файла .cpp, связанного с вашей библиотекой, вам понадобится что-то более сложное:

// library_internal.h
namespace my_unique_library_namespace {
extern Foobar global_foobar;
}

// library.cpp
#include "library_internal.h"namespace my_unique_library_namespace {
Foobar global_foobar;
}

// library_2.cpp
#include "library_internal.h"using my_unique_library_namespace::global_foobar;
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]