简体   繁体   English

为向量分配 memory 并更改大小而不调用默认构造函数

[英]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_signMessageDigest.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:上面的代码有两个小警告:

  1. You have a raw 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 ,它将初始化数组,与向量相同。
  2. The unique_ptr does not know it's own size, so you have to remember that for yourself or write a wrapper around that. unique_ptr 不知道它自己的大小,因此您必须自己记住这一点或围绕它编写一个包装器。 This also implies that you cannot resize the memory underneath it to the actual length.这也意味着您无法将其下方的 memory 调整为实际长度。 But note, that the resize for vector also just reduces the size of the vector (basically writes to the size member variabel) and does not free any capacity (the second would require a new allocation and a copy of the whole data, which can be pretty expensive).但请注意,调整向量的大小也只是减小了向量的大小(基本上写入大小成员变量)并且不会释放任何容量(第二个需要新的分配和整个数据的副本,这可以是相当昂贵)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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