- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在观看 Chandler Carruth 在 CppCon 2019 上的演讲:
There are no Zero-Cost Abstractions
其中,他举了一个例子,说明他对使用 std::unique_ptr<int>
产生的开销感到惊讶。超过 int*
;该片段大约在时间点 17:25 开始。
您可以查看compilation results他的示例片段对(godbolt.org) - 见证这一点,确实,编译器似乎不愿意传递 unique_ptr 值 - 事实上,它在底线只是一个地址 - 仅在寄存器内在直接内存中。
Carruth 先生在 27:00 左右提出的观点之一是,C++ ABI 需要按值参数(部分但不是全部;也许 - 非原始类型?非平凡可构造类型?)进行传递在内存中而不是在寄存器中。
我的问题:
PS - 不要让这个问题没有代码:
普通指针:
void bar(int* ptr) noexcept;
void baz(int* ptr) noexcept;
void foo(int* ptr) noexcept {
if (*ptr > 42) {
bar(ptr);
*ptr = 42;
}
baz(ptr);
}
唯一指针:
using std::unique_ptr;
void bar(int* ptr) noexcept;
void baz(unique_ptr<int> ptr) noexcept;
void foo(unique_ptr<int> ptr) noexcept {
if (*ptr > 42) {
bar(ptr.get());
*ptr = 42;
}
baz(std::move(ptr));
}
最佳答案
- Is this actually an ABI requirement, or maybe it's just some pessimization in certain scenarios?
一个例子是 System V Application Binary Interface AMD64 Architecture Processor Supplement 。此 ABI 适用于 64 位 x86 兼容 CPU(Linux x86_64 架构)。在 Solaris、Linux、FreeBSD、macOS、Linux 的 Windows 子系统上遵循:
If a C++ object has either a non-trivial copy constructor or a non-trivial destructor, it is passed by invisible reference (the object is replaced in the parameter list by a pointer that has class INTEGER).
An object with either a non-trivial copy constructor or a non-trivial destructor cannot be passed by value because such objects must have well defined addresses. Similar issues apply when returning an object from a function.
请注意,只有 2 个通用寄存器可用于传递 1 个带有普通复制构造函数和普通析构函数的对象,即只能传递 sizeof
不大于 16 的对象值寄存器。请参阅Calling conventions by Agner Fog有关调用约定的详细处理,特别是 §7.1 传递和返回对象。在寄存器中传递 SIMD 类型有单独的调用约定。
其他 CPU 架构有不同的 ABI。
<小时/>还有Itanium C++ ABI大多数编译器都遵守(除了 MSVC), requires :
<小时/>If the parameter type is non-trivial for the purposes of calls, the caller must allocate space for a temporary and pass that temporary by reference.
A type is considered non-trivial for the purposes of calls if:
- it has a non-trivial copy constructor, move constructor, or destructor, or
- all of its copy and move constructors are deleted.
This definition, as applied to class types, is intended to be the complement of the definition in [class.temporary]p3 of types for which an extra temporary is allowed when passing or returning a type. A type which is trivial for the purposes of the ABI will be passed and returned according to the rules of the base C ABI, e.g. in registers; often this has the effect of performing a trivial copy of the type.
- Why is the ABI like that? That is, if the fields of a struct/class fit within registers, or even a single register - why should we not be able to pass it within that register?
这是一个实现细节,但是当处理异常时,在堆栈展开期间,自动存储持续时间被销毁的对象必须相对于函数堆栈帧是可寻址的,因为此时寄存器已被破坏。堆栈展开代码需要对象的地址来调用其析构函数,但寄存器中的对象没有地址。
迂腐地,destructors operate on objects :
An object occupies a region of storage in its period of construction ([class.cdtor]), throughout its lifetime, and in its period of destruction.
如果没有为其分配可寻址存储空间,则对象不能存在于 C++ 中,因为 object's identity is its address .
当需要使用保存在寄存器中的简单复制构造函数的对象的地址时,编译器可以将对象存储到内存中并获取地址。另一方面,如果复制构造函数很重要,则编译器不能仅将其存储到内存中,而是需要调用复制构造函数,该复制构造函数需要引用,因此需要寄存器中对象的地址。调用约定可能不依赖于复制构造函数是否内联在被调用者中。
考虑这个问题的另一种方法是,对于普通可复制类型,编译器会在寄存器中传输对象的值,如果需要,可以通过普通内存存储从中恢复对象。例如:
void f(long*);
void g(long a) { f(&a); }
在具有 System V ABI 的 x86_64 上编译为:
g(long): // Argument a is in rdi.
push rax // Align stack, faster sub rsp, 8.
mov qword ptr [rsp], rdi // Store the value of a in rdi into the stack to create an object.
mov rdi, rsp // Load the address of the object on the stack into rdi.
call f(long*) // Call f with the address in rdi.
pop rax // Faster add rsp, 8.
ret // The destructor of the stack object is trivial, no code to emit.
<小时/>
钱德勒·卡鲁斯 (Chandler Carruth) 的发人深省的演讲 mentions可能有必要(除其他外)进行突破性的 ABI 更改,以实现可以改善情况的破坏性举措。 IMO,如果使用新 ABI 的函数明确选择加入新的不同链接,则 ABI 更改可能不会造成破坏。在 extern "C++20"{}
block 中声明它们(可能在用于迁移现有 API 的新内联命名空间中)。这样,只有针对具有新链接的新函数声明进行编译的代码才能使用新的 ABI。
请注意,当被调用函数已内联时,ABI 不适用。除了链接时代码生成之外,编译器还可以内联其他翻译单元中定义的函数或使用自定义调用约定。
关于c++ - 为什么 T* 可以在寄存器中传递,但 unique_ptr<T> 却不能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53331010/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!