在unique_ptr<>中使用自定义删除程序 (curl_formfree())
using custom deleter (curl_formfree()) in unique_ptr<>
我有下面的代码来使用 libcurl 发布文件。
bool FileUploadDownload::upload(const std::string& filename, const std::string& url) {
CURLcode res;
CURLFORMcode form_res;
curl_off_t speed_upload = 0;
struct curl_httppost* form_post = nullptr;
struct curl_httppost* last_ptr = nullptr;
struct curl_slist* header_list = nullptr;
static const char buf[] = "Expect: 100-continue";
std::string pure_fname = filename.substr(filename.find_last_of("/\") + 1);
res = curl_global_init(CURL_GLOBAL_ALL);
if (res != CURLE_OK) {
m_logger->errorf("curl_global_init(CURL_GLOBAL_ALL) failed: %s", curl_easy_strerror(res));
return false;
}
form_res = curl_formadd(&form_post,
&last_ptr,
CURLFORM_COPYNAME, "file",
CURLFORM_FILENAME, pure_fname.c_str(),
CURLFORM_FILE, filename.c_str(),
CURLFORM_CONTENTTYPE, "text/plain",
CURLFORM_END);
if (form_res != 0) {
m_logger->errorf("curl_formadd() failed: %s", curl_easy_strerror((CURLcode)form_res));
curl_formfree(form_post);
return false;
}
form_res = curl_formadd(&form_post,
&last_ptr,
CURLFORM_COPYNAME, "submit",
CURLFORM_COPYCONTENTS, "send",
CURLFORM_END);
if (form_res != 0) {
m_logger->errorf("curl_formadd() failed: %s", curl_easy_strerror((CURLcode)form_res));
curl_formfree(form_post);
return false;
}
if (m_curl) {
header_list = curl_slist_append(header_list, buf);
if(nullptr == header_list){
return false;
}
res = curl_easy_setopt(m_curl, CURLOPT_URL, url.c_str());
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_setopt(CURLOPT_URL) failed: %s", curl_easy_strerror(res));
curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, header_list);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_setopt(CURLOPT_HTTPHEADER) failed: %s", curl_easy_strerror(res));
curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_setopt(m_curl, CURLOPT_HTTPPOST, form_post);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_setopt(CURLOPT_HTTPPOST) failed: %s", curl_easy_strerror(res));
curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_setopt(m_curl, CURLOPT_VERBOSE, 1L);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_setopt(CURLOPT_VERBOSE) failed: %s", curl_easy_strerror(res));
curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_perform(m_curl);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_perform() failed: %s", curl_easy_strerror(res));
curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_getinfo(m_curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_getinfo(CURLINFO_SPEED_UPLOAD) failed: %s", curl_easy_strerror(res));
curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
m_logger->infof("Average upload speed: %" CURL_FORMAT_CURL_OFF_T
" megabyte/sec.n", speed_upload / (1024 * 1024));
curl_formfree(form_post);
curl_slist_free_all(header_list);
return true;
}
return false;
}
在很多情况下,上述函数失败并返回 false。在所有这些情况下,我需要打电话给curl_formfree()
并curl_slist_free_all()
。
我想使用std::unique_ptr<>
来优化它
我已经重写了上面的函数,如下所示。
bool FileUploadDownload::upload(const std::string& filename, const std::string& url) {
CURLcode res;
CURLFORMcode form_res;
curl_off_t speed_upload = 0;
auto form_delete = [&](curl_httppost * p) {
curl_formfree(p);
};
//struct curl_httppost* form_post = nullptr;
//struct curl_httppost* last_ptr = nullptr;
std::unique_ptr<curl_httppost*, decltype(form_delete)> form_post;
std::unique_ptr<curl_httppost*, decltype(form_delete)> last_ptr;
struct curl_slist* header_list = nullptr;
static const char buf[] = "Expect: 100-continue";
std::string pure_fname = filename.substr(filename.find_last_of("/\") + 1);
res = curl_global_init(CURL_GLOBAL_ALL);
if (res != CURLE_OK) {
m_logger->errorf("curl_global_init(CURL_GLOBAL_ALL) failed: %s", curl_easy_strerror(res));
return false;
}
form_res = curl_formadd(form_post.get(),
last_ptr.get(),
CURLFORM_COPYNAME, "file",
CURLFORM_FILENAME, pure_fname.c_str(),
CURLFORM_FILE, filename.c_str(),
CURLFORM_CONTENTTYPE, "text/plain",
CURLFORM_END);
if (form_res != 0) {
m_logger->errorf("curl_formadd() failed: %s", curl_easy_strerror((CURLcode)form_res));
//curl_formfree(form_post);
return false;
}
form_res = curl_formadd(form_post.get(),
last_ptr.get(),
CURLFORM_COPYNAME, "submit",
CURLFORM_COPYCONTENTS, "send",
CURLFORM_END);
if (form_res != 0) {
m_logger->errorf("curl_formadd() failed: %s", curl_easy_strerror((CURLcode)form_res));
//curl_formfree(form_post);
return false;
}
if (m_curl) {
header_list = curl_slist_append(header_list, buf);
if(nullptr == header_list){
return false;
}
res = curl_easy_setopt(m_curl, CURLOPT_URL, url.c_str());
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_setopt(CURLOPT_URL) failed: %s", curl_easy_strerror(res));
//curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, header_list);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_setopt(CURLOPT_HTTPHEADER) failed: %s", curl_easy_strerror(res));
//curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_setopt(m_curl, CURLOPT_HTTPPOST, form_post.get());
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_setopt(CURLOPT_HTTPPOST) failed: %s", curl_easy_strerror(res));
//curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_setopt(m_curl, CURLOPT_VERBOSE, 1L);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_setopt(CURLOPT_VERBOSE) failed: %s", curl_easy_strerror(res));
//curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_perform(m_curl);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_perform() failed: %s", curl_easy_strerror(res));
//curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
res = curl_easy_getinfo(m_curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_getinfo(CURLINFO_SPEED_UPLOAD) failed: %s", curl_easy_strerror(res));
//curl_formfree(form_post);
curl_slist_free_all(header_list);
return false;
}
m_logger->infof("Average upload speed: %" CURL_FORMAT_CURL_OFF_T
" megabyte/sec.n", speed_upload / (1024 * 1024));
//curl_formfree(form_post);
curl_slist_free_all(header_list);
return true;
}
return false;
}
我收到以下编译错误。
error: no match for call to ‘(std::unique_ptr<curl_httppost*, FileUploadDownload::upload(const string&, const string&)::<lambda(curl_httppost*)> >::deleter_type {aka FileUploadDownload::upload(const string&, const string&)::<lambda(curl_httppost*)>}) (curl_httppost**&)’
get_deleter()(__ptr);
你必须初始化指针。此外,lambda 的参数或指针的第一个参数也是错误的。unique_ptr
需要它引用的类型,而删除程序接受指向该类型的指针。
std::unique_ptr<curl_httppost, decltype(form_delete)>
form_post( nullptr /* required by first call of curl_formadd */,
form_delete);
也许您想创建自己的"make"函数来用更少的代码构造这些指针。
curl_formadd
需要访问指针进行初始化,并且它的第一个参数是curl_httppost**
,因此使用.get()
不会削减它。你要么必须使用中间指针(这违背了重构的目的?(,要么在这些指针周围创建一个包装器。注意,curl_formadd
已弃用。尴尬的解决方法是管理指向指针的指针。
auto form_delete = [&](curl_httppost ** p) {
curl_formfree(*p);
delete p;
};
std::unique_ptr<curl_httppost*, decltype(form_delete)>
form_post( new curl_httppost*(nullptr) /* required by first call of curl_formadd */,
form_delete);
form_res = curl_formadd(form_post.get(),
这不会消除重置指针的要求,因为基础指针是非托管的。
相关文章:
- 共享指针和具有自定义删除程序的唯一指针之间的语法差异背后的任何原因
- 如何使用 C 指针的自定义删除器创建unique_ptr?
- 在地图中使用自定义删除器存储unique_ptr
- 指向重载静态成员的函数指针 - 在unique_ptr中用作自定义删除器
- 在unique_ptr<>中使用自定义删除程序 (curl_formfree())
- 用于unique_ptr的有状态自定义删除程序
- 为什么unique_ptr不能阻止自定义删除程序的切片?
- std::unique_ptr 和自定义删除程序
- 如何使用lambda和函数作为unique_ptr的自定义删除程序
- std::unique_ptr,自定义删除程序和类型更改
- shared_ptr<EVP_PKEY> EVP_PKEY_free作为自定义删除程序会导致堆损坏
- 使用自定义删除程序返回unique_ptr的 nullptr 失败
- 对 Direct3D11 对象上使用 std::shared_ptr 的自定义删除程序
- 为shared_ptr但遇到错误指定自定义删除程序
- unique_ptr、自定义删除程序和零法则
- 带有自定义删除程序错误的 c++ 唯一指针
- 使用外部定义的自定义删除程序在头文件中定义唯一指针
- 类成员唯一指针,具有初始值设定项列表外部的自定义删除程序
- 标准::shared_ptrs的自定义删除程序
- 何时对 std::shared_ptr 使用自定义删除程序