Возвратит ли стандартный контейнер копию содержимого контейнера? - PullRequest
4 голосов
/ 18 февраля 2011

Если у меня есть функция, которая возвращает контейнер STL, я получаю копию всего содержимого стандартного контейнера?

Например, это:

void Foo( std::vector< std::string >* string_list );

лучше, чем это:

std::vector< std::string > Foo();

Имеет ли значение, что находится в контейнере?Например, возврат контейнера, подобного этому:

struct buzz {
    int a;
    char b;
    float c;
}

std::map< int, buzz > Foo();

будет более дорогостоящей операцией, чем эта:

std::map< int, int > Foo();

Спасибо, PaulH


Редактировать: Это с C ++ 03.Решение C ++ 0x, к сожалению, неприемлемо.

Edit2: Я использую компилятор Microsoft Visual Studio 2008.

Ответы [ 5 ]

6 голосов
/ 18 февраля 2011

C ++ 03, вероятно, выполнит (именованную) оптимизацию возвращаемого значения (Google RVO и NRVO).

Если эта оптимизация неприменима, C ++ 0x сделает семантику перемещения .

3 голосов
/ 18 февраля 2011

Я не был уверен на 100%, но НЕТ (спасибо комментаторам):

#include <vector>
#include <iostream>

#define LOCAL_FUN

struct A {
    A() { std::cout << "default ctor" << std::endl; }
    A(const A &a) { std::cout << "copy ctor" << std::endl; }
};

#ifdef LOCAL_FUN
std::vector<A> *pVec = NULL;
#endif

std::vector<A> func()
{
    std::vector<A> vec;
#ifdef LOCAL_FUN
    pVec = &vec;
#endif
    vec.push_back(A());
    std::cout << "returning" << std::endl;
    return vec;
}

int main(int argc, char *argv[])
{
    std::vector<A> ret = func();
#ifdef LOCAL_FUN
    if (pVec) {
        std::cout << pVec->size();
    }
#endif
}

вывод (с LOCAL_FUN):

default ctor
copy ctor
returning
1

Редактировать: Еще немного поиграть скод привел меня к забаве с локальными переменными (LOCAL_FUN).Так что действительно плохой компилятор, который не оптимизирует копирование, может на самом деле сломать этот код ...

2 голосов
/ 18 февраля 2011

Да, это будет связано с копией контейнера, но не используйте void Foo( std::vector< std::string >* string_list );.Вместо этого используйте void foo( vector<string>& string_list);.

Или просто переключитесь на C ++ 0x и используйте компилятор, который уже перенес оптимизации, реализованные в библиотеке.

0 голосов
/ 18 февраля 2011

Зависит от конструктора копирования контейнера.C ++ имеет проходную семантику по значению.Поэтому, когда вы возвращаете вектор для функции Foo (), он будет возвращен с использованием семантики значения, т.е. будет вызван конструктор копирования для копирования значения вектора.В этом случае конструктор копирования std :: vector создает новый контейнер и копирует значения.В случае передачи указателя на контейнер вы должны будете выделить память, если вы еще не распределили ее, поэтому указатель указывает на реальный контейнер, а не на нулевое значение.С точки зрения практики программирования это не очень хорошая вещь, потому что вы оставляете семантику открытой для интерпретации.Лучше было бы передать ссылку на контейнер и позволить функции заполнить контейнер требуемыми элементами.

0 голосов
/ 18 февраля 2011

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

...