直接重置结构体的内容



我实现了一个函数,它重置指针所指向的结构体的内容:

template <typename Struct>
void initialize(Struct* s)
{
*s = Struct{};
}

Struct变大(大于10K)时,我有性能问题,因为Struct是在堆栈中创建的,然后分配给*s。我想知道我是否可以改进它:

  1. 可以直接初始化吗没有临时Struct{}对象的*s?
  2. 我是否应该评估Struct的大小并在堆中构建它,如果它很大?

提前感谢

首先,您可能应该使用引用;不是指针。这样做的目的是为了避免null间接错误。

如果类是平凡的并且值初始化为零(这是通常对于大多数平凡类型的情况),那么优化器应该将您的函数编译为对memset的调用,而不需要初始化临时对象。因此,在这种情况下,应该没有理由担心。

您可以显式地调用memset,尽管在技术上,如果类包含某些类型(例如,空指针不一定具有0的表示),则不能将其移植到外来系统。

是否可以不使用临时Struct{}对象直接初始化*s ?

可以,如果你愿意改变功能的要求。目前它适用于默认可构造和移动可赋值的类。

如果直接修改指向对象,可以避免创建临时对象。在下面的示例中,没有创建Struct类型的临时对象:

constexpr void
initialize(Struct& s)
{
s.member1 = T1{};
s.member2 = T2{};

要使其泛型,可以在成员函数中执行该操作。因此,您可以指定一个要求,即指向类具有具有特定名称且没有参数的成员函数:

s.clear();

对于它们所应用的类型,可以将这两种方法结合使用:

template<class Struct>
constexpr void
initialize(Struct& s)
{
if constexpr (std::is_trivially_copyable_v<Struct>) {
// alternative 1, if you trust your optimiser
s = Struct{};
// alternative 2, if you doubt the quality of the optimiser
//    technically may have different meaning on exotic systems
std::memset(&s, 0, sizeof s);
} else {
s.clear();
}
}

如果你需要这一点来处理一些不符合这两个要求的类,那么你就需要对模板进行专门化。

如果Struct很大,我应该评估它的大小并在堆中构建它[10K]吗?

通常应该完全避免使用那么大的公共类。如果需要如此大的存储空间,可以将其包装在动态分配的类型中。像这样:

class Struct
{
private:
struct VeryLarge{/.../};
std::unique_ptr<VeryLarge> storage;
public:
// public interface

相关内容

  • 没有找到相关文章

最新更新