Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using std::tuple for reserving a space, but avoid initializing tuple elements

Tags:

c++

I want to use a std::tuple for returning a pair of values from a function. To avoid extra call to memcpy, I want first to reserve only memory y creating a tuple with uninitialized elements, then initialize tuple elements, then return the tuple from the function. Let's see an example:

#include <tuple>
#include <cstdint>
#include <cstddef>

const size_t SHA256_DIGEST_LENGTH = 256 * 8;

unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md);

struct uuid {
    uint32_t time_low;
    uint16_t time_mid;
    uint16_t time_hi;
    uint8_t bits[8];
};

void make_uuid(uuid *result);

using uuid_pair = std::tuple<uuid, uint8_t[SHA256_DIGEST_LENGTH]>;

uuid_pair make_uuid()
{
    uuid_pair result;
    make_uuid(&std::get<uuid>(result));
    SHA256((uint8_t *)&std::get<uuid>(result), sizeof(uuid), &std::get<1>(result)[0]);
    return result;
}

All works as expected, but the only problem is that the compiler fills the memory occupied by the tuple with zeros (this is 2kBytes). The problem exist because of array of uint8_t. I want to create the tuple with uninitialized array. How can I do this?

Declaring POD array and constructing tuple from it before the return is a bad idea, as NRVO doesn't happen in this case. I want exactly create the tuple, but avoid filling a large array with zeros. As a possible solution, I can create a class with custom constructor and put the array into the class. But I want to know if simpler solutions possible.

like image 941
Kirill Frolov Avatar asked Dec 10 '25 08:12

Kirill Frolov


1 Answers

std::tuple::tuple() is defined to value-initialise each member, not default-initialise it. You need to wrap your array in a type that will default-initialise the array when it is value-initialised.

But I want to know if simpler solutions possible.

No, there isn't.

Either uuid_pair is a struct you define

struct uuid {
    uuid() {} // While we are at it value-initialise uuid's members
    uint32_t time_low;
    uint16_t time_mid;
    uint16_t time_hi;
    uint8_t bits[8];
};

struct uuid_pair {
    uuid_pair() {}
    ::uuid uuid;
    uint8_t sha[SHA256_DIGEST_LENGTH];
};

uuid_pair make_uuid()
{
    uuid_pair result;
    make_uuid(result.uuid);
    SHA256(reinterpret_cast<const unsigned char *>(std::addressof(result.uuid)), sizeof(uuid), result.sha);
    return result;
}

See it on godbolt

or it only contains structs you define.

struct uuid {
    uuid() {} // While we are at it value-initialise uuid's members
    uint32_t time_low;
    uint16_t time_mid;
    uint16_t time_hi;
    uint8_t bits[8];
};

struct sha {
    sha() {}
    uint8_t bits[SHA256_DIGEST_LENGTH];
};

using uuid_pair = std::tuple<uuid, sha>;

uuid_pair make_uuid()
{
    uuid_pair result;
    make_uuid(&std::get<uuid>(result));
    SHA256(reinterpret_cast<const unsigned char *>(std::addressof(std::get<uuid>(result))), sizeof(uuid), std::get<1>(result).bits);
    return result;
}

See it on godbolt

like image 153
Caleth Avatar answered Dec 11 '25 22:12

Caleth



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!