Как его время жизни возвращаемого значения расширяется до объема вызывающей функции, когда оно связано с константной ссылкой в ​​вызывающей функции? - PullRequest
9 голосов
/ 11 апреля 2010

"Если вы возвращаете значение (не ссылку) из функции, а затем связываете его с константной ссылкой в ​​вызывающей функции, его время жизни будет расширено до объема вызывающей функции."

Итак: ДЕЛО A

const BoundingBox Player::GetBoundingBox(void)
{
    return BoundingBox( &GetBoundingSphere() );
}

Возвращает значение типа const BoundingBox из функции GetBoundingBox()

вариант I: (привязать его к константной ссылке)

const BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();

вариант II: (связать его с константной копией)

const BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();

Оба работают нормально, и я не вижу, как объект l_Bbox выходит из области видимости. (Хотя, как я понимаю, в первом варианте конструктор копирования не вызывается, и поэтому он немного лучше, чем в варианте II).

Также для сравнения я внес следующие изменения.

ДЕЛО B

BoundingBox Player::GetBoundingBox(void)
{
    return BoundingBox( &GetBoundingSphere() );
}

с вариантами: I

BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox();

и II:

BoundingBox l_Bbox = l_pPlayer->GetBoundingBox();

Объект l_Bbox все еще не выходит за рамки. Как «связать его с константной ссылкой в ​​вызывающей функции, его время жизни будет расширено до объема вызывающей функции», действительно продлить время жизни объекта до объема вызывающей функции?

Я что-то упускаю здесь тривиально?

Ответы [ 4 ]

9 голосов
/ 11 апреля 2010

Обычно временный объект (такой как объект, возвращаемый вызовом функции) имеет время жизни, которое продолжается до конца "включающего выражения". Тем не менее, временная привязка к ссылке, как правило, имеет время жизни, повышенное до времени жизни ссылки (которое может быть, а может и не быть временем жизни вызывающей функции), но есть пара исключений. Это охватывается стандартом в 12.2 / 5 «Временные объекты»:

Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом для подобъекта, к которому привязан временный объект, сохраняется в течение всего срока действия ссылки, за исключением случаев, указанных ниже. Временная привязка к элементу ссылки в конструкторе ctor-initializer (12.6.2) сохраняется до выхода из конструктора. Временная привязка к ссылочному параметру в вызове функции (5.2.2) сохраняется до завершения полного выражения, содержащего вызов.

Для получения дополнительной информации см. Следующее:

Пример, который может помочь визуализировать происходящее:

#include <iostream>
#include <string>

class foo {
public:
    foo( std::string const& n) : name(n) { 
        std::cout << "foo ctor - " << name + " created\n"; 
    };
    foo( foo const& other) : name( other.name + " copy") { 
        std::cout << "foo copy ctor - " << name + " created\n";
    };

    ~foo() { 
        std::cout << name + " destroyed\n"; 
    };

    std::string getname() const { return name; };
    foo getcopy() const { return foo( *this); };

private:
    std::string name;
};

std::ostream& operator<<( std::ostream& strm, foo const& f) {
    strm << f.getname();
    return strm;
}


int main()
{
    foo x( "x");

    std::cout << x.getcopy() << std::endl;

    std::cout << "note that the temp has already been destroyed\n\n\n";

    foo const& ref( x.getcopy());

    std::cout << ref << std::endl;

    std::cout << "the temp won't be deleted until after this...\n\n";
    std::cout << "note that the temp has *not* been destroyed yet...\n\n";
}

Который отображает:

foo ctor - x created
foo copy ctor - x copy created
x copy
x copy destroyed
note that the temp has already been destroyed


foo copy ctor - x copy created
x copy
the temp won't be deleted until after this...

note that the temp has *not* been destroyed yet...

x copy destroyed
x destroyed
4 голосов
/ 11 апреля 2010

Во-первых, время жизни временного объекта продлевается до времени жизни привязанной к нему ссылки на const, а не "в область вызывающей функции" (хотя, может быть, это то, что вы имели в виду под странной формулировкой "область вызова") функция "). Это то, что иллюстрирует ваша CASE A, где вы прикрепляете ссылку const к временной. Временный продолжает жить, пока живет ссылка. По истечении срока действия ссылки временный объект также уничтожается.

Во-вторых, ваш CASE B просто плохо сформирован, не компилируется. А именно,

BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox(); 

незаконно. В C ++ запрещается прикреплять неконстантную ссылку к временному. Если ваш компилятор это позволяет, это должно быть причудой / расширением вашего компилятора, который не имеет ничего общего с языком C ++.

2 голосов
/ 11 апреля 2010

Дело в том, что при возврате по значению значение копируется в переменную, которой вы присваиваете результат функции. (как вы и сказали - вызывается конструктор копирования ). Нет продления жизни, вы просто создаете новый объект.

При возврате по ссылке под капотом вы просто передаете указатель на переменную, определенную в функции. Таким образом, новый объект не создается, вы просто ссылаетесь на него вне функции. В этом случае время жизни переменной внутри функции увеличивается.

1 голос
/ 11 апреля 2010

Обычно, если вы возвращаете объект по значению из функции, указанный объект будет уничтожен по завершении выражения присваивания:

myclass X = getX(); // after copy constructor, the returned value is destroyed
                    // (but you still hold a copy in X)

В случае, который вы описываете, возвращаемое значение будет позже уничтожено, что позволит вам использовать его:

const myclass& X = getX();
cout << X.a << endl; // still can access the returned value, it's not destroyed
...