c++ - 在没有动态分配的情况下在构造时组合对象时避免数据的多个副本
问题描述
我们有由类表示的分层消息。它们用于通过序列化/反序列化在线程和组件之间发送消息。在我们的用例中,我们使用std::variant<InnerA, InnherB, ...>
,但为了简化,我们的代码类似于:
class Inner {
public:
Inner(uint8_t* array, uint16_t arrayLength) {
m_payloadLength = arrayLength; // Let's assume arrayLength is always < 256
memcpy(m_payload.data(), array, arrayLength));
}
std::array<uint8_t, 256> m_payload;
uint16_t m_payloadLength;
}
class Outer {
public:
Outer(const Inner& inner): m_inner(inner){};
Inner m_inner;
}
class OuterOuter {
public:
OuterOuter(const Outer& outer): m_outer(outer){};
Outer m_outer;
}
因此,要创建一个OuterOuter
我们需要做的对象
int main(int argc, char** argv){
uint8_t buffer[4] = {1,2,3,4};
Inner inner(buffer, 4);
Outer outer(inner);
OuterOuter outerOuter(outer);
addToThreadQueue(outerOuter);
}
现在的问题是,我们使用嵌入式设备,因此我们不能将动态内存与 malloc 和 new 一起使用。截至目前,有效载荷内容将被复制三次吗?一次是创建inner,一次是在Outer中调用Inner的拷贝构造函数,一次是在OuterOuter中调用Outer的拷贝构造函数?如果是这样,有没有办法在不使用动态内存的情况下避免所有这些复制?如果有办法将我的意图传递给编译器,那么可能会进行优化,如果它还没有优化它的话。
理想情况下,我们会避免OuterOuter
类采用所有子类构造参数,因为我们的树非常深并且我们使用 std::variant。在此示例中,它将是OuterOuter(uint8_t* array, uint16_t arrayLength)
,Outer(uint8_t* array, uint16_t arrayLength)
然后Outer
将构建Inner
。
解决方案
一般来说,现代编译器在优化类层次结构方面做得很好,除了填充连续的内存布局之外,它们的构造没有副作用。
例如,gcc 将您的示例编译为基本上单个类:
main:
sub rsp, 280
mov eax, 4
mov rdi, rsp
mov WORD PTR [rsp+256], ax
mov DWORD PTR [rsp], 67305985
call addToThreadQueue(OuterOuter const&)
xor eax, eax
add rsp, 280
ret
甚至除此之外,编译器还可以在某些情况下跳过一些副作用。例如,在下面的示例中,gcc 通过称为“heap elision”的过程完全摆脱了堆分配。
#include <memory>
extern int foo(int);
extern void bar(int);
struct MyStruct {
int data;
MyStruct() {
auto val = std::make_unique<int>(12);
data = foo(*val);
}
};
int main(int argc, char** argv){
MyStruct x;
bar(x.data);
}
变成:
main:
sub rsp, 8
mov edi, 12
call foo(int)
mov edi, eax
call bar(int)
xor eax, eax
add rsp, 8
ret
显然,您需要仔细检查您自己的代码库,但通常的做法仍然存在:“首先编写易于阅读和维护的代码,并且只有当编译器对它的处理不好时,您才应该费心费力地跳过箍来优化它。 "
推荐阅读
- javascript - D3.js 加载资源失败:服务器响应状态为 404(未找到)
- php - 隐藏在 laravel 7
- html - Bootstrap 布局可滚动 div
- javascript - 无法在使用 ref 和 VeeValidate 的方法中获得实际的“有效”属性
- javascript - D3.js V5 - 为什么我的条形图轴没有缩放?
- r - ggplot2中的密度图和直方图
- limit - 增加 Translate 100 文档限制
- java - 无法在 Java 中加载资源文件夹
- javascript - React Native:执行功能以在应用处于非活动状态时更改应用状态(仍在后台运行)
- java - 我如何让这个板像我想要的那样打印出来