对this post的跟进。请考虑以下内容:
class C;
C foo();
那是一对有效的声明。仅声明函数时,C
ä¸éœ€è¦å®Œå…¨å®šä¹‰ã€‚但是,如果我们è¦æ·»åŠ 以下功能:
class C;
C foo();
inline C bar() { return foo(); }
然åŽçªç„¶C
必须是完全定义的类型。但是在ä¿è¯å¤åˆ¶çœç•¥çš„情况下,ä¸éœ€è¦ä»»ä½•æˆå‘˜ã€‚没有å¤åˆ¶ç”šè‡³æ²¡æœ‰åŠ¨é™ï¼Œè¯¥å€¼åœ¨å…¶ä»–地方åˆå§‹åŒ–,并且仅在调用方(到bar
)的上下文ä¸é”€æ¯ã€‚
é‚£ä¸ºä»€ä¹ˆå‘¢ï¼Ÿæ ‡å‡†ä¸ç¦æ¢ä½¿ç”¨ä»€ä¹ˆï¼Ÿ
ç”案 0 :(得分:14)
å‡ºäºŽå…¼å®¹æ€§åŽŸå› å’Œ/或效率的考虑,ä¿è¯çš„å¤åˆ¶çœç•¥ä¹Ÿæœ‰ä¾‹å¤–。å³ä½¿å¯ä»¥å¦å¤–ä¿è¯å¤åˆ¶çœç•¥ï¼Œä¹Ÿå¯ä»¥å¤åˆ¶ç碎的å¯å¤åˆ¶ç±»åž‹ã€‚没错,如果这ä¸é€‚用,那么编译器将能够生æˆæ£ç¡®çš„代ç ï¼Œè€Œæ— éœ€äº†è§£C
的任何细节,甚至ä¸çŸ¥é“其大å°ã€‚但是编译器确实需è¦çŸ¥é“这是å¦é€‚用,为æ¤ï¼Œå®ƒä»ç„¶éœ€è¦å®Œæ•´çš„类型。
æ ¹æ®https://timsong-cpp.github.io/cppwp/class.temporary:
 Â15.2临时对象[class.temporary]
   Â已创建1个临时对象
   Â[...]
   Â(1.2)-在实现需è¦ä¼ 递或返回普通å¤åˆ¶ç±»åž‹çš„对象时(è§ä¸‹æ–‡ï¼‰ï¼Œå¹¶ä¸”
   Â[...]
   Â3当类类型
X
çš„å¯¹è±¡ä¼ é€’ç»™å‡½æ•°æˆ–ä»Žå‡½æ•°è¿”å›žæ—¶ï¼Œå¦‚æžœX
çš„æ¯ä¸ªå‰¯æœ¬æž„é€ å‡½æ•°ï¼Œmoveæž„é€ å‡½æ•°å’Œæžæž„函数都是çç¢Žçš„æˆ–åˆ é™¤çš„ï¼Œåˆ™{{1 }}è‡³å°‘å…·æœ‰ä¸€ä¸ªæœªåˆ é™¤çš„å‰¯æœ¬æˆ–ç§»åŠ¨æž„é€ å‡½æ•°ï¼Œå…许实现创建一个临时对象æ¥ä¿å˜å‡½æ•°å‚数或结果对象。临时对象分别从函数å‚æ•°æˆ–è¿”å›žå€¼æž„é€ ï¼Œå¹¶ä¸”å‡½æ•°çš„å‚数或返回对象被åˆå§‹åŒ–,就好åƒä½¿ç”¨æœªåˆ 除的çç¢Žæž„é€ å‡½æ•°æ¥å¤åˆ¶ä¸´æ—¶å¯¹è±¡ä¸€æ ·ï¼ˆå³ä½¿è¯¥æž„é€ å‡½æ•°ä¸å¯è®¿é—®æˆ–å°†ä¸ä¼šè¢«é€‰æ‹©ï¼‰é€šè¿‡é‡è½½åˆ†è¾¨çŽ‡æ‰§è¡Œå¯¹è±¡çš„å¤åˆ¶æˆ–移动)。 [注æ„:æ¤å®½å®¹åº¦å…è®¸å°†ç±»ç±»åž‹çš„å¯¹è±¡ä¼ é€’ç»™å¯„å˜å™¨ä¸çš„函数或从其ä¸è¿”回。 -尾注]
ç”案 1 :(得分:8)
这与å¤åˆ¶çœç•¥æ— 关。 foo
应该返回一个C
值。åªè¦æ‚¨å°†å¼•ç”¨æˆ–æŒ‡é’ˆä¼ é€’ç»™foo
,就å¯ä»¥ã€‚一旦您å°è¯•è°ƒç”¨foo
(就åƒbar
ä¸€æ ·ï¼‰ï¼Œå®ƒçš„å‚数大å°å’Œè¿”回值就必须在手;知é“的唯一有效方法是呈现所需类型的完整声明。
如果ç¾å使用的是引用或指针,则所有必需的信æ¯éƒ½ä¼šå˜åœ¨ï¼Œæ‚¨å¯ä»¥åœ¨æ²¡æœ‰å®Œæ•´ç±»åž‹å£°æ˜Žçš„情况下进行æ“作。这ç§æ–¹æ³•çš„å称是:pimpl ==指å‘IMPLementaion的指针,它被广泛用作éšè—æºä»£ç 库å‘行版ä¸è¯¦ç»†ä¿¡æ¯çš„一ç§æ–¹æ³•ã€‚
ç”案 2 :(得分:6)
规则ä½äºŽ[basic.lval]/9:
 Â除éžå¦æœ‰è¯´æ˜Žï¼ˆ[dcl.type.simple]),å¦åˆ™prvalue必须始终具有完整类型或void类型; ...
ç”案 3 :(得分:1)
尽管对æ¤çº¿ç¨‹å‘布了ç”案数é‡å’Œè¯„论数é‡ï¼ˆå·²å›žç”了所有我的个人问题),但我还是决定为“我们其他人â€å‘布ç”案。我最åˆä¸äº†è§£OP的功能,但现在我知é“äº†ï¼Œæ‰€ä»¥æˆ‘æƒ³åˆ†äº«ä¸€ä¸‹ã€‚äº²çˆ±çš„è¯»è€…ï¼Œå¦‚æžœæ‚¨å·²äº†è§£æ‰€æœ‰è¿™äº›å¹¶æ„Ÿåˆ°æ— èŠï¼Œè¯·ç»§ç»å‰è¿›ã€‚
@xskxzrå’Œ@hvd有效地回ç”了这个问题,但是@hvd的帖åç‰¹åˆ«æ˜¯ç”¨æ ‡å‡†è¯ï¼Œå¹¶å‡å®šè¯»è€…知é“按值回报(以åŠæ‰©å±•åRVO)的工作原ç†ï¼Œæˆ‘想并ä¸æ˜¯æ¯ä¸ªäººéƒ½ä¼šè¿™æ ·åšã€‚我以为是的,但是我å´é”™è¿‡äº†ä¸€ä¸ªé‡è¦çš„细节(当您仔细考虑时,它实际上是很明显的,但是ä»ç„¶æˆ‘错过了)。
å› æ¤ï¼Œæœ¬æ–‡ä¸»è¦å…³æ³¨äºŽæ¤ï¼Œä»¥ä¾¿æˆ‘们大家都å¯ä»¥ç†è§£ä¸ºä»€ä¹ˆï¼ˆa)OP首先想知é“为什么在编译bar()
时出现问题,然åŽï¼ˆb)éšåŽæ„è¯†åˆ°äº†åŽŸå› ã€‚
å› æ¤ï¼Œè®©æˆ‘们å†æ¬¡æŸ¥çœ‹è¯¥ä»£ç 。鉴于æ¤ï¼ˆå³ä½¿ç±»åž‹ä¸å®Œæ•´ï¼Œè¿™ä¹Ÿæ˜¯åˆæ³•çš„):
class C;
C foo();
ä¸ºä»€ä¹ˆç¼–è¯‘å™¨æ— æ³•ç¼–è¯‘æ¤ä»£ç ï¼ˆæˆ‘åˆ é™¤äº†inline
æ˜¯å› ä¸ºå®ƒæ— å…³ç´§è¦ï¼‰ï¼š
C bar() { return foo(); }
æ¥è‡ªgcc的错误消æ¯æ˜¯ï¼š
 Â错误:返回类型“ Cç±»â€ä¸å®Œæ•´
首先,被接å—çš„ç”案引用了明确ç¦æ¢å®ƒçš„æ ‡å‡†ä¸çš„相关段è½ï¼Œå› æ¤æ²¡æœ‰ä»€ä¹ˆç¥žç§˜ä¹‹å¤„。但是,OP(实际上是å‘表评论的Walter,实际上是评论员Walter)想知é“为什么。
首先,在我看æ¥è¿™å¾ˆæ˜Žæ˜¾ï¼šè°ƒç”¨è€…需è¦ä¸ºå‡½æ•°ç»“果分é…空间,而且它ä¸çŸ¥é“å¯¹è±¡æœ‰å¤šå¤§ï¼Œå› æ¤ç¼–译器å分å¤æ‚。但是我没有一个çªé—¨ï¼Œè€Œé‚£ä¸ªåœ¨äºŽæŒ‰å€¼è¿”回的工作方å¼ã€‚
现在,对于那些ä¸çŸ¥é“çš„å¯¹è±¡ï¼ŒæŒ‰å€¼è¿”å›žç±»å¯¹è±¡çš„æ–¹æ³•æ˜¯ï¼Œè°ƒç”¨è€…é€šè¿‡åœ¨å †æ ˆä¸Šä¸ºè¿”å›žçš„å¯¹è±¡åˆ†é…空间,并将指å‘该对象的指针作为éšè—å‚æ•°ä¼ é€’ç»™æ‰€è°ƒç”¨çš„å‡½æ•°æ¥è¿›è¡Œæž„é€ ï¼Œå¯¹è±¡ï¼Œå¯¹å…¶è¿›è¡Œæ“ä½œï¼Œæ— è®ºå¦‚ä½•ã€‚
但是,这是èŠèŠ±é“¾ï¼Œå› æ¤ï¼Œå¦‚果我们具有以下代ç (在调用C
之å‰æˆ‘们已完全定义bar()
,则为该代ç ):
class C
{
public:
int x;
};
C c = bar ();
c.x = 4;
然åŽåœ¨è°ƒç”¨ c
之å‰åˆ†é…bar()
的空间,然åŽå°†c
的地å€ä½œä¸ºéšè—å‚æ•°ä¼ é€’ç»™bar()
,然åŽç›´æŽ¥ä¼ 递到foo()
,最åŽå°†æž„é€ çš„å¯¹è±¡å¡«å……åˆ°æ‰€éœ€çš„ä½ç½®ã€‚å› æ¤ï¼Œç”±äºŽbar()
实际上没有对该指针进行任何æ“ä½œï¼ˆé™¤äº†ä¼ é€’æŒ‡é’ˆï¼‰ï¼Œå› æ¤å®ƒå…³å¿ƒçš„åªæ˜¯æŒ‡é’ˆæœ¬èº«ï¼Œè€Œä¸æ˜¯æŒ‡é’ˆæŒ‡å‘的内容。>
是å—?好å§ï¼Œå®žé™…上,是的。
按值返回类对象时,å°å¯¹è±¡é€šå¸¸ä¼šä½œä¸ºä¼˜åŒ–在寄å˜å™¨ï¼ˆæˆ–一对寄å˜å™¨ï¼‰ä¸è¿”回。在大多数情况下,如果对象足够å°ï¼Œç¼–译器å¯ä»¥é¿å…è¿™æ ·åšï¼ˆç¨åŽä¼šä»‹ç»æ›´å¤šå†…容)。
但是现在, bar()
需è¦çŸ¥é“这是å¦æ˜¯foo()
è¦åšçš„事情,并且出于å„ç§åŽŸå› ,它需è¦æŸ¥çœ‹å…¨éƒ¨å†…容类的声明。
å› æ¤ï¼Œæ€»è€Œè¨€ä¹‹ï¼Œè¿™å°±æ˜¯ä¸ºä»€ä¹ˆç¼–译器需è¦å®Œå…¨å®šä¹‰çš„类型æ‰èƒ½è°ƒç”¨foo()
çš„åŽŸå› ï¼Œå¦åˆ™å®ƒå°†ä¸çŸ¥é“foo
ï¼ˆï¼‰ä¼šæ˜¯ä»€ä¹ˆï¼Œå› æ¤å®ƒä¸çŸ¥é“。ä¸çŸ¥é“生æˆä»€ä¹ˆä»£ç ã€‚æ— è®ºå¦‚ä½•ï¼Œä¸â€‹â€‹æ˜¯åœ¨å¤§å¤šæ•°å¹³å°ä¸Šéƒ½å¯ä»¥ã€‚
注释:
我看了看gcc,似乎有两个(完全逻辑上)的规则æ¥ç¡®å®šæ˜¯åœ¨ä¸€ä¸ªå¯„å˜å™¨è¿˜æ˜¯ä¸€å¯¹å¯„å˜å™¨ä¸è¿”回一个类对象:
std::is_trivially_copyable<T>::value
的评估结果为true
(也许有人å¯ä»¥åœ¨æ ‡å‡†ä¸æ‰¾åˆ°æœ‰å…³æ¤å†…容的信æ¯ï¼‰ã€‚如果读者ä¸çŸ¥é“,RVO会在其最终的é™æ¢ä½ç½®ï¼ˆå³è°ƒç”¨è€…分é…çš„ä½ç½®ï¼‰ä¸ä¾èµ–æž„é€ å¯¹è±¡ã€‚ ã€‚è¿™æ˜¯å› ä¸ºæœ‰äº›å¯¹è±¡ï¼ˆä¾‹å¦‚ï¼Œæˆ‘ç›¸ä¿¡std::basic_string
çš„æŸäº›å®žçŽ°ï¼‰ä¼šåœ¨å†…å˜ä¸å››å¤„ç§»åŠ¨ï¼Œå› æ¤æ‚¨ä¸èƒ½ä»…å°†å®ƒä»¬æž„é€ åœ¨æ–¹ä¾¿çš„åœ°æ–¹ç„¶åŽmemcpy
其他地方。
å¦‚æžœæ— æ³•åœ¨è¯¥æœ€ç»ˆä½ç½®æž„é€ è¿”å›žçš„å¯¹è±¡ï¼ˆç”±äºŽç¼–ç 返回对象的函数的方å¼ï¼‰ï¼Œåˆ™RVOä¸ä¼šå‘生(怎么办?),请å‚è§ä¸‹é¢çš„实时演示( make_no_RVO()
。
作为点1b的特定示例,如果一个å°å¯¹è±¡åŒ…å«ï¼ˆå¯èƒ½ï¼‰æŒ‡å‘自身或其任何数æ®æˆå‘˜çš„æ•°æ®æˆå‘˜ï¼Œé‚£ä¹ˆæŒ‰å€¼è¿”回它会给您带æ¥éº»çƒ¦ã€‚声明ä¸æ£ç¡®ã€‚åªéœ€æ·»åŠ ä¸€ä¸ªç©ºå‰¯æœ¬æž„é€ å‡½æ•°å³å¯ï¼Œå› 为从那时起,它ä¸å†æ˜¯å¯å¤åˆ¶çš„。但是我想通常是对的,ä¸è¦ä»Žç¼–译器ä¸éšè—é‡è¦ä¿¡æ¯ã€‚
实时演示here。欢迎对æ¤å¸–åå‘表所有评论,我将尽我所能回ç”他们。