我是C ++的新手,正在尝试将Openssl
集成到我的项目中。例如此处的某些功能i2d_RSAPublicKey
接收unsigned char**
作为第二个参数,并在其中存储一些数据。我在这里曾问过类似的问题:
How to manage C++ principles with C compatible libraries and APIs
但是由于在这里使用std::string
和std::vector
并不方便,所以我决定再问一个问题。
由于std::string::c_str()
返回const
行指针,而std::vector::data()
仅返回行指针,因此它们与此功能不兼容。另外,我不认为操纵行指针将数据存储在std::string
或std::vector
中是一个好主意。
所以我的问题是,我应该使用哪种数据类型以不违反RAII
标准,并将指针的指针传递给将在其中存储一些数据的函数?
答案 0 :(得分:2)
std::unique_ptr
可以接受自定义删除器,这可以使其管理OpenSSL分配的内存。究竟需要调用什么函数来清理内容取决于分配给它的函数,但是对于您在示例中使用的i2d_RSAPublicKey
的示例,它需要包装OPENSSL_free
:
struct OpenSSLFree
{
void operator()(void* ptr)
{
OPENSSL_free(ptr);
}
};
template <typename T>
using OpenSSLPointer = std::unique_ptr<T, OpenSSLFree>;
OpenSSLPointer<unsigned char> EncodeRSAPublicKey(RSA* key)
{
unsigned char* out = nullptr;
int status = i2d_RSAPublicKey(key, &out);
if (status < 0) {
// handle error
}
return OpenSSLPointer<unsigned char>{out};
}
然后将以异常安全的方式清除包含已编码密钥的缓冲区。
在这种情况下,您也可以使用std::vector<unsigned char>
。您将不得不调用i2d_RSAPublicKey
两次:一次获得所需的缓冲区大小,再一次对数据进行实际编码:
std::vector<unsigned char> EncodeRSAPublicKey(RSA* key)
{
int len = i2d_RSAPublicKey(key, nullptr);
if (len < 0) {
// handle error
}
std::vector<unsigned char> outVec(len);
unsigned char* outPtr = outVec.data();
len = i2d_RSAPublicKey(key, &outPtr);
if (len < 0) {
// handle error
}
return outVec;
}
这可能是一个更干净的界面,但它不会在所有地方都起作用。具有自定义删除器方法的std::unique_ptr
广泛适用,但是删除器要调用的功能将再次取决于内存的分配方式。