C++ C++;不使用时返回类型';我不知道它是否';这是暂时的

C++ C++;不使用时返回类型';我不知道它是否';这是暂时的,c++,reference,virtual,constants,return-value,C++,Reference,Virtual,Constants,Return Value,假设Foo是一个相当大的数据结构。如果我不知道继承的类是否会在内部存储Foo的实例,我应该如何编写一个返回Foo实例的const虚拟函数;因此,允许通过引用返回。如果我不能在内部存储它,我的理解是我不能返回对它的const引用,因为它将是临时的。这是正确的吗?这两种选择是: virtual Foo foo() const { ... } virtual Foo const & foo() const { ... } 这里有一个不同角度的but。我看到您没有将C++0x列为标记,而是作为

假设
Foo
是一个相当大的数据结构。如果我不知道继承的类是否会在内部存储
Foo
的实例,我应该如何编写一个返回
Foo
实例的
const
虚拟函数;因此,允许通过引用返回。如果我不能在内部存储它,我的理解是我不能返回对它的
const
引用,因为它将是临时的。这是正确的吗?这两种选择是:

virtual Foo foo() const { ... }
virtual Foo const & foo() const { ... }

这里有一个不同角度的but。

我看到您没有将C++0x列为标记,而是作为任何有需要的人以及访问C++0x的人的参考,也许最好的方法是返回一个
std::unique_ptr

您只对值返回和常量引用返回之间的差异感兴趣,这只是一个优化问题,但不是。每次返回一个不同的值与每次返回一个引用(很可能是对同一个对象的引用,很可能是可以修改的)之间有着根本不同的含义:

const Foo &a = myobj.foo();
myobj.modify_the_foo();
const Foo &b = myobj.foo();
a == b; // do you want this to be true or false?
调用者需要知道它是哪一个,这既是因为程序员需要知道它的含义,也是因为编译器需要知道调用约定,所以不能将它们混合在同一虚拟函数的不同重写中。如果一些派生类想做一个,而另一些则想做另一个,那么很不幸,它们不能,就像一个可以返回
int
和另一个
float
一样

您可能会返回一个
共享\u ptr
。这样,“想要”返回引用的派生类就可以创建一个
共享的\u ptr
,删除器什么都不做(但是要注意,
shared\u ptr
会在原始对象被销毁时悬挂,而这不是您通常从返回的
shared\u ptr
中所期望的。因此,如果
Foo
比它来自的对象更长寿,那么类最好动态分配它,通过
shared\u ptr来保持它
,并返回该值的副本,而不是不执行任何操作的删除程序)。每次“希望”返回值的派生类都可以分配一个新值。因为
Foo
是“相当大的”,希望共享的成本和动态分配与创建新的返回值相比不会太痛苦

另一种可能是将
Foo
转换为一个小型pImpl样式的类,该类引用一个相当大的数据结构。如果涉及的所有内容都是不可变的,那么“想要返回引用”case可以在多个
Foo
实例之间共享大型数据结构。即使不是,也可以考虑写时复制。

这里有一种方法:

struct K 
 { 
 int ii; 
 };

class I 
  { 
  virtual K &get_k(int i)=0; 
  };

class Impl : public I 
  { 
  K &get_k(int i) { kk.ii = i; return kk; } 
  K kk; 
  };
它之所以有效,是因为您在与数据成员相同的对象中使用了kk;。Impl类的构造函数可能也很有用


编辑:更改代码格式

如果您不知道派生类是否可以存储该对象,则无法通过引用返回。因此,您的问题的严格答案是必须通过值返回

其他答案建议返回指针或智能指针,这也会起作用。但是,不存储对象的客户端必须执行动态分配,这可能比移动或复制一个相当大的对象还要慢

如果您主要关心的是避免复制,那么您可以通过降低界面的美观程度来实现这一点:

virtual void foo(Foo& putReturnvalueHere) const { ... }
指定以前会返回到传入引用中的值。这要求已构造Foo。如果不可接受,则可以传入指向将保存Foo的未构造内存区域的指针,然后使用placement new将Foo构造到该内存区域中:

virtual void foo(Foo* unconstructedFoo) const { ... }

除非你知道你在做什么,否则我不会推荐最后一个想法,你必须有最高的表现。如果表现很重要,你可能首先要考虑避免一个虚拟函数调用。

判断你有多少人对他们的答案失去了警觉,这是一个很好的问题。在设计一个课堂界面的前几天,我不得不考虑。我没有想出一个特别好的解决方案,但是我自己没有花时间问这个问题。1@0A0D我认为Herb Sutter的文章与此无关,因为在他的例子中,他通过值返回了一个对象,然后引用了它N,通过引用或按值。它仍然是一个伟大的文章,但是,或…Boo::UNQuijypTR,它在C++的C++中起着神奇的作用。0x@sehe:绝对是!我的错-我现在非常熟悉C++0x,以至于我忘记了boost曾经给过我同样的服务!boost不提供
唯一的\u ptr
类型,因为没有C++11这是不可能的,其中已经有一个标准的
唯一的\u ptr
。在C++03中
自动\u ptr
是一种方法,如果您想返回一个智能指针而不进行引用计数。@Dennis:虽然不是Boost的正式部分,但它与它紧密集成:由Howard Hinnant编写。这里的代码没有行限制。在多行上拆分它让它更具可读性。在一行上的整个类定义对我来说就像一团乱。