Когда тип возвращаемого значения является классом, как называется указатель на возвращаемое значение?

0

Пример:


class A  
{  
    ....  
    A func();  
};  

A A::func()  
{  
...  
return something;  
}  

На уровне сборки при компиляции функция A::func будет фактически иметь два параметра: первый - this указатель, а второй - адрес временного объекта A, созданного вызывающим пользователем для хранения возвращаемого значения.

Например, если мы пишем a.func(), программа создаст объект temp A (пусть вызовет его t) в стеке и передаст адрес a как первый параметр, адрес t качестве второго параметра, наконец, вызовет функция func.

Вот мой вопрос: при реализации A::func мы можем получить адрес a - это указатель на this; но есть ли у нас способ получить адрес t? Как его зовут?

Будет полезно иметь его, если, например, я хотел бы сделать некоторое выделение памяти/бесплатно, прежде чем возвращать результат.

Вот пример того, что я хочу сделать:

class A
{
    int * data;
    A func();
};

A A::func()
{
    // here "ret_p" is the pointer to the return value (let pretend that it exists)  
    ret_p->data = new int[some length];  
    ...  
    return * ret_p;  
}

Конечно, я могу создать локальный объект в A::func а затем вернуть его; но тогда программа выполнит копию между моим локальным объектом и временным объектом, созданным вызывающим. Поскольку вызывающий объект уже создал временный объект, я надеюсь, что я смогу сэкономить время и пространство, просто используя его напрямую. Это возможно?

Ну, это возможно из c++, но я все еще надеюсь...

  • 1
    Нет, такого нет. Реализация даже не должна обрабатывать возвращаемое значение так, как вы описываете.
  • 0
    Это то, для чего предназначен конструктор копирования. Используй это.
Теги:
pointers

2 ответа

0
Лучший ответ

Поставка &a для func - это форма копирования.

Нет никакой гарантии, что это произойдет вообще, и нет доступа C++ к реализации.

Я не думаю, что вы в своей голове ясно, когда вы говорите: "Я хочу сделать выделение или освобождение памяти перед возвратом результата", можете ли вы привести конкретный пример? Вероятно, все, что вам нужно, стало возможным благодаря копированию elision, операторам перемещения и RAII.


Отвечая на ваш пример, вот как вы должны это делать.

class A
{
    std :: vector <int> data;
    A func();
};

A A::func()
{
    A ret;
    ret .data .assign (some_length, 123); // or whatever;
    return ret;
}

Вероятно, это будет оптимизировать то, что вы хотите автоматически из-за копирования. Если вы считаете, что компилятор не будет копировать копию, добавьте конструктор перемещения.

A :: A (A && old)
: data (std :: move (old .data))
{
}

std::vector move constructor просто скопирует указатель. Если вы хотите знать, как это работает, ну вот и доморощенный эквивалент.

class A
{
    int * data;

    // Allocate
    A (size_t size) : data (new int [size]) {}

    // Free, only if we haven't moved.
    ~ A () {if (data) delete [] data;}

    // Move
    A (A && old) : data (old .data) {old .data = nullptr;}

    A (const A &) = delete; // or implement with a new allocation.
}
  • 0
    Я добавил пример в своем посте
  • 0
    Спасибо за подробный ответ. Я наконец нашел самый простой способ оптимизировать это: вернуть объект в качестве ссылки. A & func() работает нормально, вызывающий объект больше не создает временный объект, теперь ответственность за вызываемый объект. И когда мы оптимизируем, мы получаем правильное копирование, как и ожидалось.
Показать ещё 5 комментариев
1

В стеке нет такого параметра параметра temp A (t).

Если вы вызываете A a1 = a.func(); и return something; внутри будет вызываться copy constructor, эквивалентный этому A a1(something); , a1 и something разные.

Если вы A a1; a1 = a.func(); A a1; a1 = a.func(); и return something; внутри, a1 = something;//(operator =) a1 = something;//(operator =) будет вызываться. a1 и something разные.

Если вы вызываете A a1 = a.func(); и return A(p1); внутри это эквивалентно A a1(p1); , существует один экземпляр a1.

Если вы вызываете a.func(); напрямую, не присваивая var и не return something; внутри, ничего не происходит при возврате.

Если вы вызываете a.func(); непосредственно без присвоения var и return A(p1); внутри, объект temp будет построен, а затем немедленно уничтожен.

Если вы A a1; a1 = a.func(); A a1; a1 = a.func(); и return A(p1); внутри, будет создан объект temp, а затем operator = будет называться a1 = temp object; и тогда объект temp будет уничтожен.

Для справки.

В конце концов, A a1 = a.func() или A a1; a1 = a.func() A a1; a1 = a.func(), return something;//a var return something;//a var или return A(p1);//call constructor return A(p1);//call constructor вызовет разное поведение, я думаю, что вы можете правильно управлять памятью.

  • 0
    Это не то, что происходит, когда я проверяю разобранный код. Я должен упомянуть, что я использую Microsoft Visual Studio 2010. Я совершенно уверен, что вызывающая сторона оставляет место для локального объекта A в стеке и использует его для хранения возвращаемого значения - по крайней мере, в режиме «отладки». В режиме «релиз» этот шаг иногда пропускается из-за оптимизации, но для сложных кодов временный объект все еще существует в стеке. Вы другие описания верны.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню