引用C++是困扰我的。:)

基本的想法是,我试图返回的一个目的是从功能。我想这样做而不返回的指针(因为那么我不得不手动 delete 它的),并没有叫复制构造中,如果可能(对于高效率,当然 添加: 还因为我不知道如果我不能避免编写一份constructor).

因此,所有在所有,在这里选择这样做,我发现:

  • 功能返回的类型可以是任何一类本身(MyClass fun() { ... })或一个参考类(MyClass& fun() { ... }).
  • 功能可以构造的变量在线的返回(return MyClass(a,b,c);)或者返回现有的变量(MyClass x(a,b,c); return x;).
  • 代码,接收的可变也可以一个可变的类型:(MyClass x = fun();MyClass& x = fun();)
  • 代码,其接收的可变可以创建一个新的变量在飞行(MyClass x = fun(); 的)或者将它分配给一个现有的变量(MyClass x; x = fun();)

和一些想法:

  • 这似乎是一个糟糕的想法有返回的类型 MyClass& 因为,始终结果的变量被摧毁之前返回。
  • Copy constructor似乎只获得参与当我回来的时候一个现有的变量。返回时可变构成在该线的回报,它永远不会被称为。
  • 当我将结果分配给一个现有的变量,析构,也总是踢之前的价值是返回。此外,没有复制构造变得称,但目标变量并收到成员值的对象返回的功能。

这些结果是如此不一致的,我觉得完全糊涂了。所以,到底是什么事?我应该如何正确地构造和返回的一个目的是从功能?

有帮助吗?

解决方案

最好的方式来理解复制在C++往往是不要试图产生一个人工实例和仪器-编译器被允许两删除和增加复制构造的电话,或多或少的,因为它认为合适的。

底线-如果你需要返回的价值,回归一个值并不要担心任何"费用"。

其他提示

建议: 有效C++ 通过斯科特迈尔斯。你找到一个非常好的解释有关这个主题(和更大)。

简言之,如果返回的价值,复制构造和析构将涉及通过默认(除非编译器,优化他们走了-那是什么发生在你的一些情况下)。

如果你回通过参考(或指针)一种变量,这是当地(建造堆),你邀请麻烦,因为对象是破坏人返回,让你有一个悬空的参考结果。

规范的方式建造的对象在一个功能和返回它的价值,如:

MyClass fun() {
    return MyClass(a, b, c);
}

MyClass x = fun();

如果你用这个,你不需要担心的所有权问题,晃来晃去的参考文献等等。和编译器将最有可能的优化了额外的复制构造/析构呼吁你,所以你不需要担心的业绩。

它可以返回通过参考的一个目建造的 new (即在堆)-该目的将不会被摧毁,在返回自的功能。但是,你必须摧毁它明确地方后来通过呼叫 delete.

它也在技术上可以保存一个对象返回的价值在一个参考,如:

MyClass& x = fun();

然而,据我所知没有多少点这样做。特别是因为人们可以很容易地通过这一参考的其他部分的程序以外的目前范围;然而,所引用的对象 x 是一个本地的对象,将被销毁,尽快离开目前的范围。因此,这式可以导致讨厌的错误。

阅读有关 RVO 和NRVO(在一个词这两个代表返回值优化和命名RVO,并优化技术使用的编译器做什么你想来实现)

你会找到很多科目的在这里计算器

如果创建一个对象是这样的:

MyClass foo(a, b, c);

然后它会在堆在功能的框架。当这一职能结束,其框架是弹出栈和所有的对象,在这一框架被毁灭。 有没有办法避免这种情况。

所以如果你想要返回的一个目的一叫,你唯一的选择是:

  • 返回的通过值一个复制的构造是必需的(但称呼的复制的构造也可以优化)。
  • 返回的指针,并确保你要么使用智能指针来处理它,或者仔细删除它自己的时候完成的。

在尝试建造一个当地的对象,然后返回一个参考,本地内存到一个叫上下文是不相干的-一个叫范围不能取存储器,是当地的所谓的范围。当地存储只适用于持续时间的功能拥有它的-或者,另一种方式,同时执行仍然是在这一范围。你必须了解这个程序在C++。

关于唯一一次有意义的返回一个基准是如果你是返回的一个参照预先存在的对象。对于一个明显的例子,几乎每个法师件的功能返回参照法师该法师本身的存在之前的任何构件的功能是所谓,和继续存在之后他们被称为。

该标准允许"副本省略",这意味着复制构造并不需要被称为当你回到一个对象。这有两种形式:名返回值优化(NRVO)和匿名返回值优化(通常只是RVO).

从你在说什么,你的编译器实现RVO但不NRVO--这意味着它的 大概 一些较老的编译器。最新的汇编者实施两者。联合国-匹配dtor在这种情况下意味着它是可能的东西喜欢的海湾合作委员会3.4或左右--虽然我不记得的版本确信,有一个人在那有一个错误就像这样。当然,它也有可能是你的仪表是不完全正确,这样一个构造函数,你没有仪器的使用,配dtor是正在被调用于这一目的。

在结束,你坚持了一个简单的事实:如果你需要返回的一个目的,你需要返回的一个对象。特别是,一个基准可以只有得到访问(可能的修改版)现有的对象-但是,对象必须是构成在某一点为好。如果你可以修改某些现有的对象没有引起一个问题,这很好,很好,继续这样做。如果你需要一个新的对象不同的和独立,从这些你已经有了,来吧,做,--预先创建的对象,并通过在一个参考,可能会使返回自己的速度更快,但不会节省任何时间整体。创造的对象有关的相同的费用是否完成内部或外部的功能。任何合理的现代化编译器将包括RVO,这样你就不会支付任何额外费用,用于创建它的功能,然后返回--编译器只是将自动分配的空间物体在哪里它就会被退回,并有功能建设"地方",它将仍然可以访问之后功能返回。

基本上,回归一个基准才有意义,如果对象仍然存在之后留下的方法。编译器将警告你,如果你回的参考来的东西被破坏。

返回的一个参考,而不是一个目的值可以节省的复制的对象,这可能是显着的。

引用比较安全的指针,因为它们具有不同的symantics,但在幕后他们指针。

一个可能的解决办法,取决于使用的情况下,是以缺省-建造的目的之外的功能,采取 一个参考,并进行初始化引用的对象内的功能,像这样:

void initFoo(Foo& foo) 
{
  foo.setN(3);
  foo.setBar("bar");
  // ... etc ...
}

int main() 
{
  Foo foo;
  initFoo(foo);

  return 0;
}

现在当然,这并不工作,如果这是不可能(或不)默认构建一个 Foo 对象和随后的初始化。如果是这种情况下,然后你唯一的真正选择,以避免复制建设是一个指向一堆分配的对象。

但是再想想,为什么你试图避免复制建设放在首位。是"费用"的副本建设真的影响你的计划,或者是这一情况下的过早优化?

你是卡住有:

1)返回的指针

MyClass*func(){ //一些东西 回new MyClass(a,b,c);}

2)返回复的对象 MyClass func(){ 回MyClass(a,b,c);}

返回的一个基准是无效的,因为目的是要摧毁之后退出功能范围,除了如果该职能是一个该类的成员和准是一个可变的,是会员之类的。

没有一个直接的答案,但一个可行的建议:你也可以返回的指针,包裹在一个auto_ptr或smart_ptr.然后你会在什么控制构造和析构得到调和。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top