如何在 C++ 中“返回一个对象”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3350385/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 12:40:01  来源:igfitidea点击:

How to "return an object" in C++?

c++referenceperformancereturn

提问by phunehehe

I know the title sounds familiar as there are many similar questions, but I'm asking for a different aspect of the problem (I know the difference between having things on the stack and putting them on the heap).

我知道标题听起来很熟悉,因为有很多类似的问题,但我要求问题的不同方面(我知道将东西放在堆栈上和将它们放在堆上之间的区别)。

In Java I can always return references to "local" objects

在 Java 中,我总是可以返回对“本地”对象的引用

public Thing calculateThing() {
    Thing thing = new Thing();
    // do calculations and modify thing
    return thing;
}

In C++, to do something similar I have 2 options

在 C++ 中,做类似的事情我有 2 个选择

(1) I can use references whenever I need to "return" an object

(1) 每当我需要“返回”一个对象时,我都可以使用引用

void calculateThing(Thing& thing) {
    // do calculations and modify thing
}

Then use it like this

然后像这样使用它

Thing thing;
calculateThing(thing);

(2) Or I can return a pointer to a dynamically allocated object

(2) 或者我可以返回一个指向动态分配对象的指针

Thing* calculateThing() {
    Thing* thing(new Thing());
    // do calculations and modify thing
    return thing;
}

Then use it like this

然后像这样使用它

Thing* thing = calculateThing();
delete thing;

Using the first approach I won't have to free memory manually, but to me it makes the code difficult to read. The problem with the second approach is, I'll have to remember to delete thing;, which doesn't look quite nice. I don't want to return a copied value because it's inefficient (I think), so here come the questions

使用第一种方法我不必手动释放内存,但对我来说它会使代码难以阅读。第二种方法的问题是,我必须记住delete thing;,这看起来不太好。我不想返回复制的值,因为它效率低下(我认为),所以问题来了

  • Is there a third solution (that doesn't require copying the value)?
  • Is there any problem if I stick to the first solution?
  • When and why should I use the second solution?
  • 是否有第三种解决方案(不需要复制值)?
  • 如果我坚持第一个解决方案有什么问题吗?
  • 何时以及为何应使用第二种解决方案?

采纳答案by GManNickG

I don't want to return a copied value because it's inefficient

我不想返回复制的值,因为它效率低下

Prove it.

证明给我看。

Look up RVO and NRVO, and in C++0x move-semantics. In most cases in C++03, an out parameter is just a good way to make your code ugly, and in C++0x you'd actually be hurting yourself by using an out parameter.

查找 RVO 和 NRVO,以及 C++0x 移动语义。在 C++03 中的大多数情况下,out 参数只是让代码变得丑陋的好方法,而在 C++0x 中,使用 out 参数实际上会伤害自己。

Just write clean code, return by value. If performance is a problem, profile it (stop guessing), and find what you can do to fix it. It likely won't be returning things from functions.

只需编写干净的代码,按值返回。如果性能是一个问题,请对其进行分析(停止猜测),并找出您可以采取的措施来解决它。它可能不会从函数中返回东西。



That said, if you're dead set on writing like that, you'd probably want to do the out parameter. It avoids dynamic memory allocation, which is safer and generally faster. It does require you have some way to construct the object prior to calling the function, which doesn't always make sense for all objects.

也就是说,如果你一心想写这样的东西,你可能想要做 out 参数。它避免了动态内存分配,这更安全且通常更快。它确实需要您在调用函数之前有某种方法来构造对象,这并不总是对所有对象都有意义。

If you want to use dynamic allocation, the least that can be done is put it in a smart pointer. (This should be done all the time anyway) Then you don't worry about deleting anything, things are exception-safe, etc. The only problem is it's likely slower than returning by value anyway!

如果你想使用动态分配,至少可以把它放在一个智能指针中。(无论如何,这应该一直做)然后你不用担心删除任何东西,事情是异常安全的,等等。唯一的问题是它可能比按值返回慢!

回答by Amir Rachum

Just create the object and return it

只需创建对象并返回它

Thing calculateThing() {
    Thing thing;
    // do calculations and modify thing
     return thing;
}

I think you'll do yourself a favor if you forget about optimization and just write readable code (you'll need to run a profiler later - but don't pre-optimize).

我认为如果您忘记优化并只编写可读代码(您需要稍后运行分析器 - 但不要预先优化),您会帮自己一个忙。

回答by Martin Ingvar Kofoed Jensen

Just return a object like this:

只需返回一个这样的对象:

Thing calculateThing() 
{
   Thing thing();
   // do calculations and modify thing
   return thing;
}

This will invoke the copy constructor on Things, so you might want to do your own implementation of that. Like this:

这将调用 Things 上的复制构造函数,因此您可能想要自己实现它。像这样:

Thing(const Thing& aThing) {}

This might perform a little slower, but it might not be an issue at all.

这可能会执行得慢一点,但它可能根本不是问题。

Update

更新

The compiler will probably optimize the call to the copy constructor, so there will be no extra overhead. (Like dreamlax pointed out in the comment).

编译器可能会优化对复制构造函数的调用,因此不会有额外的开销。(就像dreamlax 在评论中指出的那样)。

回答by demetrios

Did you try to use smart pointers (if Thing is really big and heavy object), like auto_ptr:

您是否尝试过使用智能指针(如果 Thing 真的是又大又重的对象),例如 auto_ptr:


std::auto_ptr<Thing> calculateThing()
{
  std::auto_ptr<Thing> thing(new Thing);
  // .. some calculations
  return thing;
}


// ...
{
  std::auto_ptr<Thing> thing = calculateThing();
  // working with thing

  // auto_ptr frees thing 
}

回答by dreamlax

One quick way to determine if a copy constructor is being called is to add logging to your class's copy constructor:

确定是否正在调用复制构造函数的一种快速方法是将日志记录添加到类的复制构造函数中:

MyClass::MyClass(const MyClass &other)
{
    std::cout << "Copy constructor was called" << std::endl;
}

MyClass someFunction()
{
    MyClass dummy;
    return dummy;
}

Call someFunction; the number of "Copy constructor was called" lines that you will get will vary between 0, 1, and 2. If you get none, then your compiler has optimised the return value out (which it is allowed to do). If you get don't get 0, and your copy constructor is ridiculously expensive, thensearch for alternative ways to return instances from your functions.

打电话someFunction; 您将获得的“调用复制构造函数”行的数量将在 0、1 和 2 之间变化。如果没有,则您的编译器已经优化了返回值(这是允许的)。如果你得到不得到 0,并且你的复制构造函数非常昂贵,那么寻找替代方法从你的函数返回实例。

回答by Matt Joiner

Firstly you have an error in the code, you mean to have Thing *thing(new Thing());, and only return thing;.

首先,您的代码中有错误,您的意思是Thing *thing(new Thing());只有return thing;.

  • Use shared_ptr<Thing>. Deref it as tho it was a pointer. It will be deleted for you when the last reference to the Thingcontained goes out of scope.
  • The first solution is very common in naive libraries. It has some performance, and syntactical overhead, avoid it if possible
  • Use the second solution only if you can guarantee no exceptions will be thrown, or when performance is absolutely critical (you will be interfacing with C or assembly before this even becomes relevant).
  • 使用shared_ptr<Thing>. 将其取消为它是一个指针。当对Thing包含的最后一个引用超出范围时,它将为您删除。
  • 第一种解决方案在幼稚的库中很常见。它有一些性能和语法开销,如果可能,请避免使用它
  • 仅当您可以保证不会抛出任何异常,或者性能绝对至关重要时才使用第二种解决方案(在这变得相关之前,您将与 C 或程序集进行交互)。

回答by EMP

I'm sure a C++ expert will come along with a better answer, but personally I like the second approach. Using smart pointers helps with the problem of forgetting to deleteand as you say, it looks cleaner than having to create an object before hand (and still having to delete it if you want to allocate it on the heap).

我相信 C++ 专家会给出更好的答案,但我个人喜欢第二种方法。使用智能指针有助于解决忘记的问题,delete正如您所说,它看起来比必须事先创建一个对象更干净(如果要在堆上分配它,仍然必须删除它)。