我是一个真正的C ++新手,所以请耐心等待。首先让我们做好准备。
我在binary.cpp
中有一个C ++源代码,可以编译成如下所示的二进制文件:
# 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
,该方法可以在加载共享对象库之后多次调用。我在
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加载共享对象库的,因此我的lib需要在
library.h
中有一些C-Style标头: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 FFI的Ruby模块),我总是会收到错误消息:
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
let调用崩溃导致Foobar再次实例化的事实。更新2:
最终,我更简单地解决了它,使用全局可用的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。做完了! 最佳答案
所以我的第一个建议是
最简单的方法可能会起作用
并彻底摆脱单身人士。只需在您的库中创建一个全局Foobar对象:
// library.cpp
namespace {
Foobar global_foobar;
}
我将其放在一个匿名名称空间中,这样它就不会与主可执行文件或另一个库中的任何其他名为“ global_foobar”的符号发生冲突。
这确实意味着只能从library.cpp中访问它。如果您有多个链接到您的lib的.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;
关于c++ - 如何使用C++单例返回仅初始化一次的对象,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17862547/