草庐IT

c++ - 声明一个空的析构函数可以防止编译器调用 memmove() 来复制连续的对象

coder 2024-01-30 原文

考虑以下 Foo 的定义:

struct Foo {
    uint64_t data;
};

现在,考虑以下 Bar 的定义,它具有与 Foo 相同的数据成员,但有一个 用户-声明析构函数:

struct Bar {
    ~Bar(){} // <-- empty user-declared dtor
    uint64_t data; 
};

使用带有 -O2 的 gcc 8.2,函数 copy_foo():

void copy_foo(const Foo* src, Foo* dst, size_t len) {
    std::copy(src, src + len, dst);
}

产生以下汇编代码:

copy_foo(Foo const*, Foo*, size_t):
        salq    $3, %rdx
        movq    %rsi, %rax
        je      .L1
        movq    %rdi, %rsi
        movq    %rax, %rdi
        jmp     memmove
.L1:
        ret

上面的汇编代码调用memmove() 来执行连续Foo 对象的复制。但是,下面的函数 copy_bar()copy_foo() 完全相同,但对于 Bar 对象:

void copy_bar(const Bar* src, Bar* dst, size_t len) {
    std::copy(src, src + len, dst);
}

生成以下汇编代码:

copy_bar(Bar const*, Bar*, size_t):
        salq    $3, %rdx
        movq    %rdx, %rcx
        sarq    $3, %rcx
        testq   %rdx, %rdx
        jle     .L4
        xorl    %eax, %eax
.L6:
        movq    (%rdi,%rax,8), %rdx
        movq    %rdx, (%rsi,%rax,8)
        addq    $1, %rax
        movq    %rcx, %rdx
        subq    %rax, %rdx
        testq   %rdx, %rdx
        jg      .L6
.L4:
        ret

此汇编代码不调用memmove(),而是自行执行复制。

当然,如果 Bar 被定义为:

struct Bar {
    ~Bar() = default; // defaulted dtor
    uint64_t data;
};

然后,这两个函数会产生相同的汇编代码,因为 Foo 也有一个默认的析构函数。

为什么用户在类中声明空析构函数会阻止编译器生成对 memmove() 的调用以复制该类的连续对象?

最佳答案

std::memmove只能用于 TriviallyCopyable 的对象,这需要一个 trivial destructor .普通析构函数要求析构函数不是用户提供的。

在您的 Bar 代码中:

struct Bar {
    ~Bar(){} // <-- empty user-declared dtor
    uint64_t data; 
};

析构函数是用户提供的,因此 Bar 不是 TriviallyCopyable。因此,编译器生成对 std::memmove 的调用通常是不正确的。


根据 as-if 规则,编译器理论上可以检测到析构函数为空,因此等同于微不足道,但很明显,此优化未包含在 std::copy 的实现中>.

implementation of std::copy from libstdc++使用相当于 std::is_trivially_copyable它被定义为报告 Bar 不可平凡复制。启用此优化需要 libstdc++ 具有特殊类型特征来检测这种特殊情况,这可以通过编写 ~Bar() = default;

轻松避免

关于c++ - 声明一个空的析构函数可以防止编译器调用 memmove() 来复制连续的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52283359/

有关c++ - 声明一个空的析构函数可以防止编译器调用 memmove() 来复制连续的对象的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  4. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  5. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  6. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

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

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

  8. ruby-on-rails - active_admin 目录中的常量警告重新声明 - 2

    我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA

  9. 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

  10. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

随机推荐