2012-12-17 1 views
3

Предположим, есть метод, который возвращает std::set:C++ возвращает класс в ссылку const или нет?

std::set<string> MyClass::myMethod() const 
{ 
    std::set<string> result; 
    // ... some code to fill result ... 
    return result; 
} 

В вызывающей стороны, мы можем сохранять результат myMethod двумя способами:

void MyClass::test() 
{ 
const std::set<string> s1 = myMethod(); // 1 
const std::set<string>& s2 = myMethod(); // 2 (using reference) 
// ... some code to use s1 or s2 ... 
} 

Мои вопросы:

  • Есть ли разница между ними?
  • Какой способ лучше и эффективен?

ответ

3

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

На практике RVO, скорее всего, ударит так, что они должны быть примерно одинаковыми.

+0

Требуется ли первая версия копии (РВО в сторону), если тип имеет движение конструктор и/или оператор назначения перемещения? – Kos

+0

На практике вы предпочитаете, какой путь? – deepmax

+0

@MasoudM. первый. –

4
const std::set<string> s1 = myMethod(); // 1 

Возвращение myMethod копируется в s1. В зависимости от размера это может занять много времени.

const std::set<string>& s2 = myMethod(); // 2 (using reference) 

Сохраняется ссылка на временный возврат myMethod. Это приводит к тому, что один экземпляр меньше указанного выше, поэтому он немного быстрее (при отсутствии оптимизации).

Это special case feature, который используется для ссылки на переменную, которая в противном случае прекратила бы существовать при этом ;. Это работает ТОЛЬКО, если это const&, что в вашем примере это или ссылка Rvalue - && (спасибо @Kos).

+0

Не только 'const &', это также относится к '&&'. – Kos

+0

@Kos Это ссылка Rvalue is not it .. Я боюсь, что я не обновил себя на семантике перемещения и связанных с ней изменениях. Пожалуйста, не стесняйтесь редактировать и добавлять детали. –

+0

В C++ 03 ссылка будет (или может быть) инициализирована для ссылки на копию, а не на возвращаемый объект. Формально нет никакой разницы между этими двумя. –

2

Да, они разные:

  1. const std::set<string> s1 = myMethod(); // 1: скопировать временный объект

  2. const std::set<string>& s2 = myMethod(); // 2 (using reference): срок службы временного удлиняется, это избежать одной копии

См Guru of the week #88. Обратите внимание, что компилятор может оптимизировать это, сделав его одинаковым с точки зрения эффективности.

+0

Обратите внимание, что компилятор может «пессимизировать» инициализацию ссылки для использования копии. –

1
  1. Первая версия будет создавать std::set объект, и он будет перемещен в этой линии

    const std::set<string> s1 = myMethod();

  2. Это продлит срок службы std::set объекта, созданного в методе:

    const std::set<string>& s2 = myMethod();

Таким образом, по производительности оба делают то же самое.

2

На практике вряд ли будет какая-либо разница.Я проверил следующее с g++ 4.7.2:

#include <string> 

extern std::string f(); 
extern void g(const std::string&, const std::string&); 

int main() { 
    std::string  x = f(); 
    const std::string& y = f(); 
    g(x, y); 
} 

И он производит идентичный код для обоих вызовов f():

LEHB0: 
     call __Z1fv 
LEHE0: 
     leaq 16(%rsp), %rdi 
LEHB1: 
     call __Z1fv 
LEHE1: 
     leaq 16(%rsp), %rsi 
+1

+1 Хороший тест, а как насчет переносимости? Можем ли мы доверять всем компиляторам C++ для того же вывода? – deepmax

+0

@MasoudM: Мы явно не можем ожидать, что * все * компиляторы будут вести себя определенным образом. Однако я бы ожидал, что любой хороший компилятор выполнит эту оптимизацию. – NPE

+0

Какой путь лучше, и вы обычно выбираете? – deepmax

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