我已经实现了一个函数,它重置指针指向的结构的内容:
template <typename Struct>
void initialize(Struct* s)
{
*s = Struct{};
}
Struct
当变大(超过 10K)时我会遇到性能问题,因为Struct
在堆栈中创建然后分配给*s
. 我想知道我是否可以改进它:
- 是否可以在没有临时对象的情况下直接初始化?
*s
Struct{}
Struct
如果它很大,我应该评估它的大小并在堆中构建它吗?
先感谢您
我已经实现了一个函数,它重置指针指向的结构的内容:
template <typename Struct>
void initialize(Struct* s)
{
*s = Struct{};
}
Struct
当变大(超过 10K)时我会遇到性能问题,因为Struct
在堆栈中创建然后分配给*s
. 我想知道我是否可以改进它:
*s
Struct{}
Struct
如果它很大,我应该评估它的大小并在堆中构建它吗?先感谢您
首先,您可能应该使用参考;不是指针。这样做的目的是避免空间接错误。
如果类是平凡的并且值初始化为零(这通常是大多数平凡类型的情况),那么优化器应该将您的函数编译为对 的调用memset
,而无需初始化临时对象。所以在这种情况下应该没有理由担心。
您可以memset
显式调用,尽管如果类包含某些类型(例如,空指针不一定具有零的表示),这在技术上不能移植到外来系统。
是否可以在没有临时 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