[英]allocate memory for a vector and change size without calling default constructor
I am using a openssl EVP_PKEY_sign
where the signature buffer size is already known and can be allocated using a vector.我正在使用 openssl
EVP_PKEY_sign
签名缓冲区大小已知并且可以使用向量分配。
size_t SignatureLength;
std::vector<unsigned char> Signature;
EVP_PKEY_sign(EvpPkeyCtx, NULL, &SignatureLength, MessageDigest.data(), MessageDigest.size());
Signature.resize(SignatureLength);
EVP_PKEY_sign(EvpPkeyCtx, Signature.data(), &SignatureLength, MessageDigest.data(), MessageDigest.size());
Signature.resize(SignatureLength);
I am using the Signature.data()
to get the raw pointer to the buffer used by the vector.我正在使用
Signature.data()
来获取指向向量使用的缓冲区的原始指针。 The first call to EVP_PKEY_sign
gives the maximum length of the output signature buffer.第一次调用
EVP_PKEY_sign
给出了 output 签名缓冲区的最大长度。 On calling resize the buffer is filled-up with 0's which cause an additional overhead making it an O(n) operation where only O(1) allocation is needed.在调用 resize 时,缓冲区会被 0 填满,这会导致额外的开销,使其成为 O(n) 操作,其中只需要 O(1) 分配。
Alternative is to call reserve but it fails as it only allocates memory and post calling EVP_PKEY_sign
again the MessageDigest.size()
would still be zero and resizing it to actual signature length(from the second call) then would overwrite the buffer with default values.另一种方法是调用reserve,但它失败了,因为它只分配memory 并再次调用
EVP_PKEY_sign
, MessageDigest.size()
仍然为零并将其调整为实际签名长度(来自第二次调用),然后会用默认值覆盖缓冲区。
What is the efficient way to do this?这样做的有效方法是什么?
Signatures tend to be short.签名往往很短。 Setting a low number of values to 0 is an extremely fast operation and thus not likely to be a significant cost in relation to the single allocation for example and especially not in relation to the calculation of the signature which has linear complexity at best.
将少量值设置为 0 是一种非常快的操作,因此对于例如单个分配,尤其是对于充其量具有线性复杂性的签名的计算而言,这不太可能是显着的成本。
It is possible to avoid the initialisation using a custom allocator .使用自定义分配器可以避免初始化。
You could simplify by using the constructor to allocate the memory upon creating the vector:您可以通过使用构造函数在创建向量时分配 memory 来简化:
EVP_PKEY_sign(EvpPkeyCtx, nullptr, &SignatureLength, ...
std::vector<unsigned char> Signature(SignatureLength);
EVP_PKEY_sign(EvpPkeyCtx, Signature.data(), ...
This doesn's affect the initialisation though.不过,这不会影响初始化。
I agree with the other answer that the value initialization does now matter.我同意另一个答案,即值初始化现在很重要。 If you want to get around it nonetheless, you could use
std::unique_ptr<unsigned char[]>
instead:尽管如此,如果你想绕过它,你可以使用
std::unique_ptr<unsigned char[]>
代替:
size_t SignatureLength;
EVP_PKEY_sign(EvpPkeyCtx, NULL, &SignatureLength, MessageDigest.data(), MessageDigest.size());
std::unique_ptr<unsigned char[]> Signature{new char[SignatureLength]};
EVP_PKEY_sign(EvpPkeyCtx, *Signature, &SignatureLength, MessageDigest.data(), MessageDigest.size());
I think that many times, an std::unique_ptr<T[]>
works quite nicely with C-APIs that would in C be used with some manually managed array or stack buffer.我认为很多时候,
std::unique_ptr<T[]>
与 C-API 配合得很好,在 C 中可以与一些手动管理的数组或堆栈缓冲区一起使用。 The above code has two small caveats:上面的代码有两个小警告:
new
in there.new
在那里。 That's a bit ugly, but no problem, since constructing an std::unique_ptr
from a raw pointer cannot throw and you are not calling any potentially throwing constructors with the new
so this is will never leak.std::unique_ptr
不能抛出,而且你没有用new
调用任何可能抛出的构造函数,所以它永远不会泄漏。 If you use make_unique
, it will value initialize the array, same as the vector.make_unique
,它将初始化数组,与向量相同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.