在 C++11 中将结构作为输出参数传递

Passing structs as output parameters in C++11

本文关键字:输出 参数传递 结构 C++11      更新时间:2023-10-16

在 C++11 中将结构作为输出传递的最佳实践是什么?

当所有权由外部函数维护时,应该在外部函数还是内部函数中创建结构?

而且,它应该是一个shared_ptr还是unique_ptr?

例如,假设我有一个复杂的结构,大致如下:

struct Error {
    string Code;
    string Message;
    string Details;
    string Command;
};
struct Response {
    stringstream Data;
    bool Success;
    Error Error;
};

然后,从调用函数中,我想声明:

Response r;
getResponse( url, &r );

getResponse 应定义为:

getResponse( string, shared_ptr );    or
getResponse( string, unique_ptr );

另外,应该如何声明字符串和字符串流? 它们也应该被shared_ptr吗?

在这种情况下,getResponse 函数不希望响应完成后与响应有任何关系,响应本身的生存期应由调用方决定。

声明和填充结构的最佳做法是什么?

现代编译器非常擅长优化从函数返回值的方式,因此通常按值返回:

// Just return by value
Response getResponse(const std::string& url)
{
    Response r;
    // ...
    return r;
}

好的,基于我无法复制数据的事实,在我的情况下,返回类型的响应将不起作用。

看来我有两个选择:

int getResponse( const std::string &url, shared_ptr<Response> )

unique_ptr<Response> getResponse( const std::string &url )

所以它变成了代码:

if( !getResponse( "http://...", response ) )
   // report error

而不是

if( getResponse( "http://..." ) == nullptr )
   // report error

就编码模式/最佳实践而言,哪个更可取?

我使用第二个的优点是,我可以检查结果而无需查看nullptr。

首先,Galik 的答案是正确的,只是按值返回。那么很明显,你的两种方法都是错误的。堆栈中有一个对象,该对象的生存期由编译器完美管理,您无法delete该对象(或使用智能指针对其进行delete)。

如果您对不按值返回有一些特殊的兴趣(也许该对象在紧密循环中重用,并且您希望重用字符串缓冲区......很可能不是这样,但请耐心等待),我建议您使用参数引用或指针

void getResponse(std::string const& url, Response& resp);
void getResponse(std::string const& url, Response* resp);

第一个参数更清楚,因为第二个参数不是可选的,无需测试或担心它可能为 null。另一方面,某些编码约定需要第二种形式,因为从调用方的角度来看,函数将修改对象可能更清楚(在调用中getResponse(url, &response) url参数不会被修改,response可能会(&)。例如,谷歌的编码风格就是这种情况。 就个人而言,我更喜欢参考,但你知道...在罗马时...如果您的商店有政策,请遵循它。

为什么你应该在这里按值返回的一个略有不同的答案是你的结构的内容。 如果对象的内容移动成本低,则应按值返回。Move 语义将自动启动,因为编译器知道您返回的本地范围对象即将被销毁。

如果你的对象不是便宜的移动/复制,我会说通过引用/指针传递的经典建议仍然适用。 unique_ptr/shared_ptr 只有在解决对象所有权问题时才能发挥作用。 即。 我正在将此对象传递给一个函数,该函数现在拥有它。 如果所有权没有被改变,请使用通过引用和指针传递的经典建议。