如何实现一个创建新对象并返回对它的引用的C++方法
How to implement a C++ method that creates a new object, and returns a reference to it
我有一个带有以下方法的C++AuthenticatingProxy类实例。此方法创建一个Response对象,然后用状态更新该对象,然后返回。由于响应对象的内部原因,它不能被复制(即,我不能简单地按值返回)。
const Response& AuthenticatingProxy::Get(const std::string& host,
const std::string& path,
const http_headers& headers)
{
static Response response;
// do the HTTP call, and set response's state here
return response;
}
AuthenticatingProxy类中的此方法可能会发生许多调用,因此在此处设置静态变量并不理想。有人能提出一个解决方案,返回一个在函数退出时没有被破坏的引用吗?谢谢
在我的研究中,最接近的是最佳实践页面,其中提到"通过引用而非价值返回,在那里创建了一个大对象",但我还没有找到一个例子!所有的例子都是针对传入然后返回的引用,或者针对int&样式引用—而不是在函数本身中创建对象实例的引用。
我认为解决方案可能存在于将函数返回响应作为值,但在调用代码中使用const变量来捕获它。不过,不确定这是否只适用于int-我发现的所有示例都使用基本类型。非常感谢您的帮助。
由于响应对象的内部原因,它不能被复制(即,我不能简单地按值返回)。
您正在描述一个在C++03中存在但已不存在的问题。
以老爱的std::fstream
为例
基本上,在*内部,它包含一个文件描述符/句柄,用于从文件中读取/向文件中写入
由于C++的性质和设计,fstream
析构函数关闭了该文件句柄,以清理对象并防止句柄泄漏。
由于fstream
对象的内部原因,无法按值返回。通过值返回它意味着以某种方式防止析构函数关闭该文件句柄,或者使复制构造函数以某种方式复制该句柄。即使不是不可能,也很难获得跨平台解决方案。更不用说复制内部缓冲区是完全错误的。
因此,在C++11之前,您不能按值返回fstream
然后发明了移动语义。
在C++11中,您可以移动对象,而不是复制它。在fstream
示例中,move构造函数浅层复制文件句柄,同时使原始文件句柄指针无效。原始对象析构函数将检查原始文件句柄,查看它是否无效并跳过关闭它
这是解决你问题的惯用方法。虽然你不能复制对象,但你肯定可以为它实现移动语义。对象的内部将被移动到返回值,而原始对象在某种程度上保持"空"。
在这个SO答案中可以找到对移动语义的很好解释:什么是移动语义?
如果该解决方案也不可行,请在动态内存存储("堆")中声明对象,并通过一些智能指针返回它。
如何实现一个创建新对象并返回参考
即使可以,也不要做。
*是的,文件句柄可以存储在streambuff
对象中,我简单地描述了这个问题。
C++中有三个存储类。静态、自动和动态。
退出作用域时,自动对象将被销毁,因此不能返回对本地自动变量的引用。
您可以返回对静态的引用,但正如您所说,它不适合您。
剩下的唯一选项是动态。然而,动态对象必须以某种方式销毁,并且当您返回对动态创建的对象的引用时,调用方不清楚它是否应该处理它的销毁。因此,这在技术上是可能的,但内存管理没有很好的解决方案†。此外,动态分配可能代价高昂。
†当您坚持返回参考资料时,不会。但是,如果您返回std::unique_ptr
,这个问题就会消失。
那么,让我们重新审视自动变量的选项。我说过,您不能返回对局部自动变量的引用。从更高范围返回对自动变量的引用是完全可以的。如何访问这样的变量?当然要使用参考资料!
const Response& AuthenticatingProxy::Get(const std::string& host,
const std::string& path,
const http_headers& headers,
Response& response)
{
// do the HTTP call, and set response's state here
return response; // might as well return void because caller already has a reference
}
当动态分配过于昂贵并且编译器不支持移动语义时,这是一个典型的解决方案。在这个解决方案中,函数中实际上没有创建任何对象。它只是为调用者创建的对象设置数据。对象实际上可以有任何存储类型,这无关紧要。
然而,最好的解决方案是按价值回报。你说Response
是不可复制的。但由于C++11,只要类型是可移动的,这并不妨碍按值返回。大多数编译器甚至忽略了这一举措。
Response response;
// do stuff to response
return response;
感谢您的提示,我找到了一个答案。。。
(尽管正如其他人所提到的,它给调用者留下了内存管理的问题。这可以满足我的需求。)
本页对此进行了描述:http://www.codeproject.com/Articles/823658/Using-auto-for-declaring-variables-of-move-only-ty
这是我的新方法声明:-
const Response* AuthenticatingProxy::Get(const std::string& host,
const std::string& path,
const http_headers& headers)
{
auto && response = new Response;
// do stuff to response
return std::move(response);
}
因此,我返回一个指针,但以上述方式使用std::move和auto会返回一个可以在调用代码中管理的指针。
编辑:-
好的,所以根据反馈,我现在在AuthenticatingProxy.cpp:-中有这个
std::unique_ptr<Response> AuthenticatingProxy::Get(const std::string& host,
const std::string& path,
const http_headers& headers)
{
Response* response = new Response;
// do call and fill out the response
return std::unique_ptr<Response>(response);
}
我的中间连接类正在这样做:-
std::unique_ptr<Response> Connection::getDocument(const std::string& uri) {
return Connection::_proxy.Get(_serverUrl, "/v1/documents?uri=" + uri);
}
(注意:我不得不从代理和连接类中删除constness,否则我会遇到使用已删除的副本构造函数的编译问题)
我的客户端代码(main)是这样做的:-
// MUST keep local reference to unique_ptr for this to work!!!
const std::unique_ptr<Response> rp = connection->getDocument(uri);
Response* response = rp.get();
...
std::cout << "This is JSON doc " << uri << ": " << std::endl << response->Json() << std::endl;
这似乎很好用,并且包含了关于这个线程的所有建议。现在这样正确吗?如果是的话,感谢大家的帮助!
- 从父类方法返回子类对象
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 让bool方法返回其他整数
- 不能将方法返回的值用于另一个方法
- 如何实现 Front() 方法以返回模板化双向链表C++的第一个元素?
- 从私有成员变量的成员方法返回unique_ptr
- 我的模板类方法返回错误类型?
- std::find,返回所有找到的值的替代方法,而不仅仅是存在重复的向量的第一个值
- QtQuick - qml:28:错误:未知方法返回类型:自定义类型
- 方法错误"not all control paths return a value"和方法不返回值
- GRPC C++ TLS 客户端 grpc::SslCredentials() 方法不返回
- 我无法使用C++指针指向类方法返回的 std::vector
- 如何在工厂方法中返回指向基于基础操作系统的派生类的有效指针
- 将传入的网络"char*"数据转换为"uint8_t"并返回的安全方法是什么?
- C++方法是否可以根据传递给构造函数的参数具有不同的返回类型?
- EnQueue 方法在循环队列中未正确返回C++?
- 应用于const和非const对象的引用返回方法
- 在vc++ PPL中,如何创建一个同步返回的任务返回方法
- 为什么从浮点返回方法返回双精度不会在 c++ 中导致任何错误/警告
- 这个返回方法叫什么?