简体   繁体   中英

Reset directly the content of a struct

I have implemented a function that resets the content of the structure to which a pointer points:

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

I have performance issues when Struct becomes big (above 10K) because Struct is created in the stack and then assigned to *s . I was wondering if I could improve it:

  1. Is it possible to initialize directly *s without the temporary Struct{} object?
  2. Should I instead evaluate the size of Struct and build it in the heap if it is big?

Thank you in advance

Firstly, you should probably use a reference; not a pointer. The point of this is to avoid null indirection bugs.

If the class is trivial and value initialise to zero (which is typically the case for most trivial types), then the optimiser should compile your function into a call to memset , without any need for initialisation of a temporary object. So there should be no reason to worry in that case.

You could call memset explicitly, although that is technically not portable to exotic systems in case the class contains certain types (for example, null pointer does not necessarily have the representation of zero).

Is it possible to initialize directly *s without the temporary Struct{} object?.

Yes, if you're willing to change the requirements of the function. Currently it works for classes that are default constructible and move assignable.

You can avoid creation of a temporary object if you modify the pointed object directly. In following example, there are no temporaries of type Struct created:

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

To make this generic, the operation could be performed in a member function. Thus, you could specify a requirement that the pointed class has a member function with particular name and no parameters:

s.clear();

You can combine both approaches for types which they apply to:

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();
    }
}

If you need this to work with some classes that conforms to neither requirement, then you'll need to specialise the template.

Should I instead evaluate the size of Struct and build it in the heap if it is big [10K]?

You generally should avoid having public classes that large entirely. If you need such large storage, you could wrap it in a type that allocates it dynamically. Something like this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM