вектор еще существует? - PullRequest
2 голосов
/ 14 ноября 2011
std::vector<float> someOp(void)
{
    using namespace std;
    vector<float> results;
    // some operations done to results
    return results;
}

int main(void)
{
    using namespace std;
    vector<float> &results = someOp();
}

Существует ли вектор, возвращаемый someOp, в пространстве стека someOp () или в пространстве стека main ()?

Я склонен полагать, что он не копируется / не перемещаетсяв пространство стека main (), поскольку вектор результатов имеет одинаковый адрес внутри обоих методов.

Ответы [ 4 ]

5 голосов
/ 14 ноября 2011

Также это не является допустимым C ++ (и не компилируется g ++).

Кажется, вы пытаетесь сохранить ссылку на возвращенный results, но это невозможно, поскольку возвращенный results существует в кадре стека someOp, и, хотя он все еще будет там сразу после someOp() возвращается, будет перезаписано в какой-то момент в будущем.

3 голосов
/ 14 ноября 2011

Это немного сложнее.

Да, изначально оно находится в пространстве стека someOp.Но так как вы возвращаете по значению, копия сделана.Так что это не потеряно (пока).

Однако, когда вы сохраняете его в vector<float> &results, вы сохраняете ссылку на него.Который становится недействительным после окончания утверждения.Возвращенный вектор является промежуточным звеном, который уничтожается после окончания оператора.

Таким образом, конечный результат состоит в том, что vector<float> &results становится висящим «указателем».

РЕДАКТИРОВАТЬ: (см. комментарии)

Очевидно, код вообще не должен компилироваться.Но это в VS2010.Так что мой ответ относится только к случаю, когда он компилируется.

2 голосов
/ 14 ноября 2011

Это не компилируется переносимо - в стандарте C ++ вы не можете привязать временный (std::vector<float>, возвращаемый someOp в данном случае) к неконстантной ссылке.

0 голосов
/ 14 ноября 2011

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

type f() {
   type x;        // [1]
   return x;      // [2]
}
int main() {
   type m = f();  // [3]
   m.const_function();
}

ВВ приведенной выше программе концептуально есть 3 объекта, x внутри f, возвращаемое значение без имени и, наконец, m внутри main.x создается в [1], затем копируется в возвращенный объект в [2], который в конечном итоге используется для копирования конструкции m в [3].

Теперь вернемся к эталонному случаю:

type f() {
   type x;                // [1]
   return x;              // [2]
}
int main() {
   type const & r = f();  // [3]
   r.const_function();
}

Концептуально происходит то же самое.Объект x создается в [1] и копируется в возвращаемое значение в [2], теперь в [3] это возвращаемое значение используется не для инициализации r, а для инициализации безымянного объекта, введенногокомпилятор.Наконец, в [3] постоянная ссылка связана с неназванным объектом.На этом этапе объект без имени находится в контексте main.

Что касается того, что на самом деле происходит в текущих компиляторах, соглашение о вызовах определяет, как реализуется интерфейс функций.Соглашение о вызовах для функции, которая возвращает объект, который не помещается в регистры, реализуется (во всех известных мне компиляторах), передавая дополнительный скрытый указатель на функцию.То есть вызывающая сторона (в данном случае main) резервирует место в стеке, а затем передает указатель на это местоположение вызываемой стороне.Это место, где вызывающая сторона и вызываемая сторона соглашаются, что возвращенный объект будет жить.Это означает, что вызывающая сторона может зарезервировать пространство для m в исходном примере или для неназванного объекта во втором случае и передать указатель. Это удаляет один из объектов из уравнения как m (или неназванный объект)и возвращенный объект одинаков.Следующий шаг выполняется компилятором при обработке вызываемого, если он может определить, что x будет возвращено во всех путях кода, он не создаст x в своем собственном стеке, но непосредственно в памяти, на которую ссылается скрытыйуказатель.Когда это будет сделано, чистый эффект состоит в том, что в программе будет один объект:

main получит память и передаст указатель на f, f создастx в этой области памяти (которая находится в main стековом пространстве) и возврат к main, в случае ссылки const компилятор alias безымянным объектомимя ссылки.

(Примечание: ссылка и неназванный объект не одинаковы, их типы могут фактически отличаться, но ссылка будет псевдонимом для безымянного объекта, который предоставляет имя для него)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...