使用 future 时获取 C2280(尝试引用已删除的函数)
Getting C2280 (attempting to reference a deleted function) when using future
我正在使用poco库,我正在尝试将它们包装成一个更好的HTTPClient,我可以在几行中随时随地使用,并使它们异步。为此,我正在使用 std::future 和自定义响应结构。但是,出于某种原因,它告诉我它正在尝试引用已删除的函数。我没有删除任何东西,所以我真的不知道为什么它会这么说。
httpclient.h
#include <Poco/Net/HTTPSClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/Exception.h>
#include <Poco/URI.h>
#include <future>
#include <map>
typedef struct response {
std::istream& is;
Poco::Net::HTTPResponse& response;
} RES;
class HttpClient {
public:
static std::future<RES> get(Poco::Net::HTTPSClientSession& session, Poco::URI url, std::map<std::string, std::string> headers = {});
};
httpclient.cpp
#include "httpclient.h"
std::future<RES> HttpClient::get(Poco::Net::HTTPSClientSession& session, Poco::URI url, std::map<std::string, std::string> headers) {
return std::async(std::launch::async, [&session, url, headers](){
try {
std::string path(url.getPathAndQuery());
if (path.empty()) path = "/";
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path, Poco::Net::HTTPMessage::HTTP_1_1);
request.add("Content-Length", "0");
if (headers.size() > 0) {
for (std::map<std::string, std::string>::const_iterator itr = headers.begin(); itr != headers.end(); ++itr) {
request.add(itr->first, itr->second);
}
}
Poco::Net::HTTPResponse _res;
session.sendRequest(request);
std::istream& is = session.receiveResponse(_res);
return RES { is, _res };
}
catch (Poco::Exception & exc) {
OutputDebugStringA(exc.displayText().c_str());
}
});
}
主.cpp
Poco::Net::initializeSSL();
Poco::URI uri("https://www.google.com");
const Poco::Net::Context::Ptr context = new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(), context);
std::future<RES> response = HttpClient::get(session, uri, {});
response.get();
这是我得到的确切错误:C2280: response &response::operator =(const response &)': attempting to reference a deleted function future:line 332
.
谢谢!
该错误告诉您无法复制response
对象,并且您正在尝试执行此操作。
struct response {
std::istream& is; // can't be copied: istream( const istream&) = delete;
Poco::Net::HTTPResponse& response; // also not copyable or movable
};
但是,您显示的代码中没有任何内容可以尝试执行此操作。
receiveResponse()
返回对std::istream
的引用,如果引发,该引用将出现问题。当你发现异常时,你没有任何东西可以返回,所以你没有 - 并进入未定义行为的土地。
您不妨读取 lambdaasync
中的数据,并将其直接存储在RES
中。
#include <Poco/Exception.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/Net/HTTPSClientSession.h>
#include <Poco/Net/SecureStreamSocket.h>
#include <Poco/URI.h>
#include <future>
#include <iostream>
#include <map>
#include <vector>
#include <memory>
// a slightly modified version of your RES struct
struct RES {
std::vector<std::string> data{}; // the document data
// using a unique_ptr to make HTTPResponse easier to move
std::unique_ptr<Poco::Net::HTTPResponse>
response = std::make_unique<Poco::Net::HTTPResponse>();
bool ok = false; // if reading was done without an exception
};
class HttpClient {
public:
static std::future<RES> get(Poco::Net::HTTPSClientSession& session,
Poco::URI url,
std::map<std::string, std::string> headers = {});
};
std::future<RES> HttpClient::get(Poco::Net::HTTPSClientSession& session,
Poco::URI url,
std::map<std::string, std::string> headers) {
return std::async(std::launch::async, [&session, url, headers]() {
RES res;
try {
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET,
url.getPathAndQuery(),
Poco::Net::HTTPMessage::HTTP_1_1);
// add request headers
for(const auto&[field, value]: headers)
request.add(field, value);
session.sendRequest(request);
std::istream& is = session.receiveResponse(*res.response);
// read document data
std::string line;
while(std::getline(is, line))
res.data.push_back(line);
res.ok = true; // reading was done without an exception
} catch(Poco::Exception& exc) {
std::cout << exc.displayText().c_str() << "n";
}
// always return according to what you declared
return res;
});
}
用法示例:
class SSLInitializer {
public:
SSLInitializer() { Poco::Net::initializeSSL(); }
~SSLInitializer() { Poco::Net::uninitializeSSL(); }
};
int main() {
SSLInitializer sslInitializer;
Poco::URI uri{"https://www.google.com/"};
const Poco::Net::Context::Ptr context = new Poco::Net::Context(
Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, 9,
false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
Poco::Net::HTTPSClientSession sess(uri.getHost(), uri.getPort(), context);
std::future<RES> fut_res = HttpClient::get(sess, uri);
fut_res.wait();
RES res = fut_res.get();
std::cout << std::boolalpha << "Response OK: " << res.ok << "n---n";
if(res.ok) {
Poco::Net::HTTPResponse& header = *res.response
std::cout << "HTTPResponse header:n";
for(const auto& [field, value] : header) {
std::cout << field << " = " << value << "n";
}
std::cout << "--- DOCUMENT DATA ---n";
for(const auto& s : res.data) {
std::cout << s << "n";
}
}
}
您遇到的问题是由于类Poco::Net::HTTPResponse
不可复制。它的复制构造函数和赋值运算符都声明为私有的。因此,不可能将副本制作为副本。
我真的认为为每个 http 请求生成一个新线程是矫枉过正的。我可以理解您想要这样做的原因,但您必须记住,创建新线程涉及一些开销。你最好只使用 Poco 类,或者,如果你愿意,可以在它们上面包装一个东西。您的 http 请求可能会通过为每个请求生成一个新线程来运行得更慢。
我可以建议对您的结构 RES 稍作更改:
typedef struct response {
Poco::Net::HTTPResponse::HTTPStatus status;
std::string contents;
} RES;
此结构现在可用于在发出请求后保存来自Poco::Net::HTTPResponse
对象的数据。然后借助将std::istream
的内容输出到std::string
std::string Gulp(std::istream& in)
{
std::string response(std::istreambuf_iterator<char>(in), {});
return response;
}
您可以在 main.cpp 中执行此操作:
Poco::Net::initializeSSL();
Poco::URI uri("https://www.google.com");
const Poco::Net::Context::Ptr context = new
Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", "", "", Poco::Net::Context::VERIFY_NONE, 9, false, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
Poco::Net::HTTPSClientSession session(uri.getHost(), uri.getPort(), context);
std::string path(uri.getPathAndQuery());
if (path.empty()) path = "/";
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_GET, path, Poco::Net::HTTPMessage::HTTP_1_1);
Poco::Net::HTTPResponse _res;
session.sendRequest(request);
std::istream& is = session.receiveResponse(_res);
RES response{ _res.getStatus(), Gulp(is) };
- 移动赋值运算符;尝试引用已删除的函数.我该如何解决这个问题?
- C++ 尝试在不存在的构造函数中引用已删除的函数(使用 rapidJson)
- 为什么通过 vector<reference_wrapper> 的元素删除引用的值<T>不会使向量无效?
- 在引用初始化中使用已删除的复制构造函数进行复制初始化
- CMake 引用我在 ~/bin 中创建的随机 shell 脚本(即使我删除了它)?
- 删除对象(具有不同类型)的引用时会发生什么情况?
- 使用函数引用指向节点的指针删除链表中的节点?
- unique_ptr实现接口时对已删除函数的引用
- 无法引用该函数" std:: variant <_Types...> operator =",因为此函数已被删除
- 从尝试引用已删除函数的矢量 C++ 中删除对象
- unique_ptr,您引用的是已删除的函数
- 试图引用已删除函数数组的相等运算符
- 错误:在类型 "blah blah" 的绑定引用中删除限定符以初始化"some other blah blah"
- 使用 future 时获取 C2280(尝试引用已删除的函数)
- 删除通过取消引用新对象初始化的对象
- C++引用已删除函数错误
- 是否可以删除取消引用的指针
- 尝试引用已删除的函数
- 如何在C++上使用对象引用删除对象
- BOOST共享指针导致冗余引用删除