2009-07-21 2 views
2

В следующем сценарии:временный объект, параметры функции и неявное приведение

struct Foo 
{ 
    // ... 
    operator Bar() {... } // implicit cast to Bar 
} 

Foo GetFoo() { ... } 
void CallMeBar(Bar x) { ... } 

// ... 
CallMeBar(GetFoo()); 

[редактировать] фиксированный оператор приведения, д о [/ править]

GetFoo возвращает временный объект типа Foo , Сохраняется ли этот объект до тех пор, пока CallMe не вернется? Что говорит стандарт?

Я понимаю, что если CallMe примет Foo, временный объект не будет уничтожен до тех пор, пока не вернется CallMe. Тем не менее, я не уверен, что имплицитные изменения меняются, и только временный Bar, как ожидается, выживет.


Типичный случай будет Foo = CString, Бар = символ *, то есть бар ссылок на данные, принадлежащие (и), освобожденные от Foo.

+1

Все здесь по значению, является то, что предназначено или некоторые ссылки участвует? – Naveen

ответ

7

Независимо от броска, временный объект (ы) «выживают» вызов CallMe() функции из стандарта C++:

12.2.3 [...] Временные объекты уничтожаются как последний шаг в оценке fullexpression (1.9), который (лексически) содержит точку, в которой они были созданы. [...]

1.9.12 A fullexpression - это выражение, которое не является подвыражением другого выражения.

1

Пока вы возвращаете их по стоимости, они выживают до тех пор, пока CallMeBar не будет закончен.

Ваш оператор-оператор немного выключен. Должно быть:

struct Foo 
{ 
    // ... 
    operator Bar() {... } // implicit cast to Bar 
} 

См., Например, http://msdn.microsoft.com/en-us/library/ts48df3y(VS.80).aspx

1

Способ, которым я склонен думать об этом - волшебный символ - это точка с запятой. Точка с запятой запускает деструкторы.

2

Он сохранится, но полагаться на этот факт может сбивать с толку и может заставить клиентов вашего кода достичь стандарта C++, задавать вопросы о переполнении стека и т. Д .;-). Например, что происходит, когда кто-то делает:

Bar b = GetFoo(); 
CallMeBar(b); 

На этот раз, Foo ступала CallMeBar называется, но большинство программистов хотели бы преобразования, чтобы создать независимый объект, и, следовательно, для кода вести себя так же, как:

CallMeBar(GetFoo()); 

Вот почему std::string не имеет неявное приведение к char*, в отличии от CString «s броска к LPCTSTR. Вместо этого std::string имеет функцию c_str() член, который имеет такое же ограничение, но делает его немного более очевидным в вызывающий код, что это не реальное преобразование:

CallMePtr(GetString().c_str()); // OK 

char* p = GetString().c_str(); // Bad 
CallMePtr(p);      // Badness manifests 

const string &s = GetString(); // use "the most important const" 
CallMePtr(s.c_str());    // Best be on the safe side 
+0

Этот первый пример на самом деле хорошо, не так ли? GetFoo() возвращает Foo, который преобразуется в строку и копируется в переменную b. Затем он живет долго и счастливо :) –

+0

Ну, если бросок - правильное обращение, конечно.Но если CallMeBar полагается на уже существующий Foo, о чем спрашивает OP, возникает проблема. Если приведение от Foo to Bar означает, что результирующий Bar действителен только до тех пор, пока Foo является, то я предполагаю, что это верно для копии. Модель, на которую мы основываемся, - это отличное от CString до LPCTSTR, которое, как мне кажется, является плохой идеей. На самом деле это не преобразование, это аксессор к внутреннему компоненту CString. –

+0

А, я вижу. Я интерпретировал Bar как полнотелый тип значения все время, но это предположение на самом деле не поддерживается кодом, опубликованным. Не против меня :) –

Смежные вопросы