如何完美地结合c++异常处理程序与C库?



我尝试在c++程序中使用libcurl:

size_t getContainersCallback(const char *buff, size_t size, size_t buff_size, void *data) {
char newBuff[buff_size + 1];
memset(newBuff, 0, buff_size + 1);
memcpy(newBuff, buff, buff_size);
static_cast<string *>(data)->append(newBuff);
return size * buff_size;
}
int main() {
CURL *curl = curl_easy_init();
string responseBody{};
...
if (curl_easy_perform(curl) == CURLE_OK) {
json j = json::parse(responseBody.c_str());
...
}
curl_easy_cleanup(curl);
return 0;
}

但是当获取的数据不是完整的json时,函数json::parse会抛出异常,导致指针curl不能被回收。

下面的方法感觉太愚蠢了,迫使我再写一行代码:

try {
json j = json::parse(responseBody.c_str())
...

} catch (exception &e) {
curl_easy_cleanup(curl);
throw e;
}
curl_easy_cleanup(curl);

在使用其他C库时,您也应该遇到类似的问题。还有其他更好的方法吗?

应该使用析构函数来处理资源释放。std::unique_ptr是足够灵活的,你可以重新使用它:

// include curl, etc.
#include <memory>
struct CurlDeleter {
void operator()(CURL* p) const noexcept {
if (p) {
curl_easy_cleanup(p);
}
}
};
using CurlPtr = std::unique_ptr<CURL, CurlDeleter>;
int main() {
CurlPtr curl{curl_easy_init()};
// ...
if (curl_easy_perform(curl.get()) == CURLE_OK) {
json j = json::parse(responseBody.c_str());
// may throw, doesn't matter
}
// curl_easy_cleanup is called automatically
}
try {
json j = json::parse(responseBody.c_str())
} catch (exception &e) {
curl_easy_cleanup(curl);
}
curl_easy_cleanup(curl);

我认为你不需要curl_easy_cleanup在catch中,因为你正在从异常中恢复,那么函数将被调用两次。


这不是C的特定问题,如果清理你有一个异常,有些情况下并不是所有的东西都被正确地清理了,在这些情况下你必须小心。

如果你真的想要一些能很好地处理异常的东西,你需要做你开始的事情,在需要的时候点缀try语句。您可以在curl对象周围编写一个包装器,它将通过RAII处理清理。或者您可以使用现有的包装器,如http://www.curlpp.org/.

最新更新