草庐IT

c++ - 没有调用单例的构造函数

coder 2023-11-13 原文

我有单例类,旨在用于一个线程(GUI 线程), 为了防止错误使用,我添加了 assert

//header file
class ImageCache final {
public:
    ImageCache(const ImageCache &) = delete;
    ImageCache &operator=(const ImageCache &) = delete;
    static ImageCache &instance()
    {
       static ImageCache cache;
       return cache;
    }
    void f();
private:
    QThread *create_context_ = nullptr;
    ImageCache();
};

//cpp
ImageCache::ImageCache()
{
    create_context_ = QThread::currentThread();
    qInfo("begin, cur thread %p\n", create_context_);
}

void ImageCache::f()
{
    assert(create_context_ == QThread::currentThread());
}

一切正常,但在一台机器上 ImageCache::f 断言失败, 我无法直接访问那台机器(因此出现了这个问题)。

有趣的是,根据日志 ImageCache::ImageCache 根本没有被调用,断言失败是因为

assert(0 == QThread::currentThread());

我将 ImageCache::instance 的实现从头文件移动到 .cpp 文件, 将更新后的源代码发送给这些机器的用户(我的一切正常), 他重建并按预期开始工作。

我向他询问已编译的二进制文件(有断言失败和没有断言失败),它们之间的唯一区别是 ImageCache::instance 实现的位置,

并比较汇编器。

调用 ImageInstance::instance().f() 没有区别 根本, ImageInstance::instance 的反汇编器有一个区别,

失败的看起来像这样:

 static ImageCache &instance()
   4938f:   55                      push   %rbp
   49390:   48 89 e5                mov    %rsp,%rbp
   49393:   41 54                   push   %r12
   49395:   53                      push   %rbx
    {
        static ImageCache cache;
   49396:   48 8b 05 bb db 23 00    mov    0x23dbbb(%rip),%rax        # 286f58 <_ZGVZN10ImageCache8instanceEvE5cache@@Base-0x2150>
   4939d:   0f b6 00                movzbl (%rax),%eax
   493a0:   84 c0                   test   %al,%al
   493a2:   0f 94 c0                sete   %al
   493a5:   84 c0                   test   %al,%al
   493a7:   74 5c                   je     49405 <_ZN10ImageCache8instanceEv+0x76>
   493a9:   48 8b 05 a8 db 23 00    mov    0x23dba8(%rip),%rax        # 286f58 <_ZGVZN10ImageCache8instanceEvE5cache@@Base-0x2150>
   493b0:   48 89 c7                mov    %rax,%rdi
   493b3:   e8 08 b7 fe ff          callq  34ac0 <__cxa_guard_acquire@plt>

好的是这样的:

ImageCache &ImageCache::instance()
{
   50c12:   55                      push   %rbp
   50c13:   48 89 e5                mov    %rsp,%rbp
   50c16:   41 54                   push   %r12
   50c18:   53                      push   %rbx
    static ImageCache cache;
   50c19:   0f b6 05 98 94 23 00    movzbl 0x239498(%rip),%eax        # 28a0b8 <_ZGVZN10ImageCache8instanceEvE5cache>
   50c20:   84 c0                   test   %al,%al
   50c22:   0f 94 c0                sete   %al
   50c25:   84 c0                   test   %al,%al
   50c27:   74 50                   je     50c79 <_ZN10ImageCache8instanceEv+0x67>
   50c29:   48 8d 3d 88 94 23 00    lea    0x239488(%rip),%rdi        # 28a0b8 <_ZGVZN10ImageCache8instanceEvE5cache>
   50c30:   e8 cb 3d fe ff          callq  34a00 <__cxa_guard_acquire@plt>

区别在于

//bad
mov    0x23dbbb(%rip),%rax 
movzbl (%rax),%eax
//good
movzbl 0x239498(%rip),%eax

我的解释是,出于某种原因,第一个变体的 %eax 寄存器得到了错误的值,因此决定全局对象在未初始化时被初始化。在第二种情况下,一切都按预期工作。

那么是编译器失败 (gcc (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0/amd64/linux) 还是我应该在 .cpp 出于某种原因, 还是其他导致代码生成不同的原因,例如某些编译器错误可能导致此失败?代码是使用 -O0 -std=c++11 和 cmake 在编译依赖于 Qt 库的共享库时自动添加的一些其他标志编译的。

我还询问使用 fprintf(stderr 而不是 qInfo 的测试代码, 并且用户在第二种情况下看到输出,而在第一种情况下看不到输出。

最佳答案

原始答案

据我了解,头文件中的函数存在的问题是您可以获得多个定义,然后行为未指定。

从本质上讲,编译器可能会生成多个函数 instance,每个包含该 header 的编译单元都有一个,因此如果它们在链接时没有合并/消除,每个函数都会有自己的变量.

在 Windows 中,如果我们在多个 DLL 中编译相同的代码,其中某些变量在每个动态库中重复,我们可能会遇到类似的问题。

然后会发生的情况是,因为每个客户端都有自己的拷贝,一个客户端所做的更改不会被另一个翻译单元(您的问题)或另一个 DLL(我的问题)中的另一个客户端看到。

通过将定义移动到源文件中,您将得到一个单一的定义,从而避免了这个问题。

在C++中,如果你不遵循规范,你经常会得到未定义的行为。程序员知道他在做什么。

更新

如前所述,在评论中,根据当前标准,我的假设可能是错误的。因此,问题也可能是过时的编译器编译器错误

对正在发生的事情的可能解释:

在许多情况下,当编译器合并重复项时,代码将是相同的,因此选择哪个代码不会有任何区别。在这里,假设编译器为静态变量分配了 2 个不同的地址(每个编译单元一个)并以某种方式内联对 instance() 的调用,它使用原始变量而不是合并的变量(选择)一个,它可以解释观察到的行为。

关于c++ - 没有调用单例的构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53841757/

有关c++ - 没有调用单例的构造函数的更多相关文章

  1. ruby - 难道Lua没有和Ruby的method_missing相媲美的东西吗? - 2

    我好像记得Lua有类似Ruby的method_missing的东西。还是我记错了? 最佳答案 表的metatable的__index和__newindex可以用于与Ruby的method_missing相同的效果。 关于ruby-难道Lua没有和Ruby的method_missing相媲美的东西吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/7732154/

  2. ruby-on-rails - rails 目前在重启后没有安装 - 2

    我有一个奇怪的问题:我在rvm上安装了ruby​​onrails。一切正常,我可以创建项目。但是在我输入“railsnew”时重新启动后,我有“程序'rails'当前未安装。”。SystemUbuntu12.04ruby-v"1.9.3p194"gemlistactionmailer(3.2.5)actionpack(3.2.5)activemodel(3.2.5)activerecord(3.2.5)activeresource(3.2.5)activesupport(3.2.5)arel(3.0.2)builder(3.0.0)bundler(1.1.4)coffee-rails(

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  6. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  7. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  8. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  9. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  10. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

随机推荐