Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Вернуть из функции std::map


Автор: Alca 23.9.2008, 11:30
Вернуть из функции std::map оптимально быстрым способом?
(без передачи std::map по ссылке или указателю в функцию)
Код

typedef std::map<std::string, std::string, std::less<std::string>> TStringMap;
TStringMap Func() {
    TStringMap smInfo;
    //заполняю 
    return smInfo;
}

Автор: Alek86 23.9.2008, 11:38
Код
typedef std::map<std::string, std::string, std::less<std::string>> TStringMap;
typedef std::auto_ptr<TStringMap> StringMapPtr;
StringMapPtr Func() {
    StringMapPtr p_smInfo = new StringMap;
    //заполняю 
    return p_smInfo;
}

Автор: Lazin 23.9.2008, 11:41
Цитата(Alca @  23.9.2008,  11:30 Найти цитируемый пост)
typedef std::map<std::string, std::string, std::less<std::string>> TStringMap;

можно less не указывать, оно по умолчанию less
Код

void Func(TStringMap& out) 
{
    //заполняю 
    out[...] = ...;
}

TStringMap mymap;
Func(mymap);

Автор: Torsten 23.9.2008, 12:00
Цитата(Alca @  23.9.2008,  11:30 Найти цитируемый пост)
без передачи std::map по ссылке или указателю в функцию

ну остается 3 варианта :
1) вернуть по значению  (крайне не эффективно)
2) вернуть по указателю (нужно сохранить обезательно указатель и не забыть потом очистить память)
3) по ссылке - тут сразу будет креш программы, да и компилятор должен предупредить о local variable.

Наиболее удачен вариант возращать smart_ptr или принимать в smart_ptr, т.е. чтобы после возращения указателя функцией у нее у указателя появился хозяин.
Ну и еще как извращенный вариант - сделать переменную static и возращать по ссылки или указателю.


Автор: Lazin 23.9.2008, 12:14
Цитата(Alca @  23.9.2008,  11:30 Найти цитируемый пост)
без передачи std::map по ссылке или указателю в функцию

не обратил внимания, а что в этом плохого?

Автор: Alca 23.9.2008, 12:20
Цитата

а что в этом плохого?

Ничего.
Код

TStringMap Func()

Для меня так нагляднее.
Всем спасибо.

Автор: maxim1000 23.9.2008, 18:49
Цитата(Torsten @  23.9.2008,  12:00 Найти цитируемый пост)
вернуть по значению  (крайне не эффективно)

измерения проводились?
а то есть такая штука, как RVO - return value optimization, которая как раз и направлена на подобные ситуации...

Добавлено через 56 секунд
другео дело, что я не знаю, в каких конкретно случаях она осуществляется, и насколько можно на неё полагаться
но с другой стороны, если на оптимизацию не полагаться, много чего из stl нужно выбросить...

Автор: Alca 25.9.2008, 14:24
Цитата

измерения проводились?

Вот решил потестить:
Код

#include <windows.h>
#include <fstream>
#include <string>
#include <iostream>
#include <stdio.h>
#include <map>
#include "CXString.hpp"
#include "CFsoString.hpp"
#include "CPerform.hpp"  //GetThreadTimes

using namespace std;
typedef std::map<std::string, std::string, std::less<std::string>> TStringMap;
//---------------------------------------------------------------------------
//вернуть по значению
TStringMap FuncA() {
    TStringMap dic;
    
    dic["Key0"] = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
    dic["Key1"] = "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
    dic["Key2"] = "2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222";
    dic["Key3"] = "3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333";
    dic["Key4"] = "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444";
    dic["Key5"] = "5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555";
    dic["Key6"] = "6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666";
    dic["Key7"] = "7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777";
    dic["Key8"] = "8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888";
    dic["Key9"] = "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999";
    
    return dic;
}
//---------------------------------------------------------------------------
//вернуть по ссылке
bool FuncB(TStringMap &smDic) {
    smDic["Key0"] = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
    smDic["Key1"] = "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
    smDic["Key2"] = "2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222";
    smDic["Key3"] = "3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333";
    smDic["Key4"] = "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444";
    smDic["Key5"] = "5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555";
    smDic["Key6"] = "6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666";
    smDic["Key7"] = "7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777";
    smDic["Key8"] = "8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888";
    smDic["Key9"] = "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999";
    
    return true;
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[]) {
    CPerform P("___Testing perfomance.txt");
    
    //-------------------------------------
    //A
    P.vStart(2);
    TStringMap smDicA;
    for (int i = 0; i < 10000; i ++) {
        smDicA = FuncA();
    }
    P.vStop();
    //-------------------------------------

    Sleep(10);
    
    //-------------------------------------
    //B
    P.vStart(2);
    TStringMap smDicB;
    for (int i = 0; i < 10000; i ++) {
        FuncB(smDicB);
    }
    P.vStop();
    //-------------------------------------
    
    P.vOpenLog();        


    system("pause");

    return 0;
}
//---------------------------------------------------------------------------

Результат на лицо:
Цитата

DEBUG
[2008-09-25 14:15:33]  ------------------------------
[2008-09-25 14:15:43]  0:00:10:375
[2008-09-25 14:15:45]  0:00:01:906
[2008-09-25 14:15:48]  ------------------------------

RELEASE
[2008-09-25 14:16:15]  ------------------------------
[2008-09-25 14:16:16]  0:00:00:328
[2008-09-25 14:16:16]  0:00:00:031
[2008-09-25 14:16:18]  ------------------------------

maxim1000, +1

Автор: Lazin 25.9.2008, 14:35
я думаю разница скорее из-за того, что во втором случае, создание TStringMap вынесено за цикл, а в первом происходит при каждой итерации

Автор: maxim1000 25.9.2008, 15:25
и не только создание, а ещё и удаление предыдущего
подобная оптимизация основывается на том, что для приёма результата работы функции создаётся объект прямо в той же строчке, т.е. его не нужно чистить от предыдущих данных
тогда вместо (создание снаружи, создание внутри, присваивание) можно делать просто (создания снаружи)

я бы предложил попробовать так:
Код

#include <windows.h>
#include <fstream>
#include <string>
#include <iostream>
#include <stdio.h>
#include <map>
#include "CXString.hpp"
#include "CFsoString.hpp"
#include "CPerform.hpp"  //GetThreadTimes
using namespace std;
typedef std::map<std::string, std::string, std::less<std::string>> TStringMap;
//---------------------------------------------------------------------------
//вернуть по значению
TStringMap FuncA() {
    TStringMap dic;
    
    dic["Key0"] = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
    dic["Key1"] = "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
    dic["Key2"] = "2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222";
    dic["Key3"] = "3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333";
    dic["Key4"] = "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444";
    dic["Key5"] = "5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555";
    dic["Key6"] = "6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666";
    dic["Key7"] = "7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777";
    dic["Key8"] = "8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888";
    dic["Key9"] = "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999";
    
    return dic;
}
//---------------------------------------------------------------------------
//вернуть по ссылке
bool FuncB(TStringMap &smDic) {
    smDic["Key0"] = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
    smDic["Key1"] = "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111";
    smDic["Key2"] = "2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222";
    smDic["Key3"] = "3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333";
    smDic["Key4"] = "4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444";
    smDic["Key5"] = "5555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555";
    smDic["Key6"] = "6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666";
    smDic["Key7"] = "7777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777";
    smDic["Key8"] = "8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888";
    smDic["Key9"] = "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999";
    
    return true;
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[]) {
    CPerform P("___Testing perfomance.txt");
    
    //-------------------------------------
    //A
    P.vStart(2);
    for (int i = 0; i < 10000; i ++) {
      TStringMap smDicA = FuncA();
      std::cout<<smDicA.begin()->first<<std::endl;//to prevent too much optimization :)
    }
    P.vStop();
    //-------------------------------------
    Sleep(10);
    
    //-------------------------------------
    //B
    P.vStart(2);
    for (int i = 0; i < 10000; i ++) {
      TStringMap smDicB;
      FuncB(smDicB);
      std::cout<<smDicB.begin()->first<<std::endl;//to prevent too much optimization :)
    }
    P.vStop();
    //-------------------------------------
    
    P.vOpenLog();        
    system("pause");
    return 0;
}
//---------------------------------------------------------------------------


Добавлено через 2 минуты и 51 секунду
P.S. Честно говоря, я сам не знаю толком условия работы RVO, могу только предполагать smile

Автор: Alca 25.9.2008, 15:45
Код

/*GetTickCount()*/
DEBUG:
[2008-09-25 15:38:24]  ------------------------------
[2008-09-25 15:38:41]  0:00:16:546
[2008-09-25 15:38:54]  0:00:13:187
[2008-09-25 15:39:01]  ------------------------------

RELEASE
[2008-09-25 15:39:48]  ------------------------------
[2008-09-25 15:39:53]  0:00:05:516
[2008-09-25 15:39:58]  0:00:04:985
[2008-09-25 15:40:03]  ------------------------------

P.S. Вот вам и возврат по значению...

Автор: W4FhLF 25.9.2008, 16:21
В данном случае копирование объекта вносит издержки равные 10% от времени исполнения(если, конечно, это именно копирование объекта). Но эти издержки будут расти с увеличением размера возвращаемого объекта. 

Alca, вощьми map размером не 10 элементов, а 1000, разница должна быть более ощутима. 

Автор: maxim1000 25.9.2008, 16:22
нннда... похоже, не сработала...

Добавлено через 1 минуту и 49 секунд
вообще, конечно, зря я написал std::cout - довольно медленная операция, можно было бы просто суммировать первые символы строк, чтобы поменьше влиять на статистику
но всё равно разница остаётся...

Автор: Alca 25.9.2008, 17:16
map на 1000 элементов (убрал std::cout):
Код

/*GetTickCount()*/
DEBUG:
[2008-09-25 17:06:42]  0:01:38:391
[2008-09-25 17:08:03]  0:01:20:735

RELEASE
[2008-09-25 17:08:33]  0:00:02:094
[2008-09-25 17:08:35]  0:00:02:078

Автор: J0ker 25.9.2008, 17:33
Цитата(maxim1000 @  23.9.2008,  18:49 Найти цитируемый пост)
а то есть такая штука, как RVO - return value optimization, которая как раз и направлена на подобные ситуации...

RVO выполняется в случае
Код

return type(params);

и случаях котоые могут быть к ему сведены

Автор: MTWizard 7.5.2009, 15:08
Цитата(J0ker @  25.9.2008,  17:33 Найти цитируемый пост)
RVO выполняется в случае return type(params); и случаях котоые могут быть к ему сведены

есть ещё NRVO smile

Автор: Alca 7.5.2009, 15:10
NRVO - это чего такое?

Добавлено через 2 минуты
Нашел
http://alenacpp.blogspot.com/2008/02/rvo-nrvo.html

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)