какой код эффективнее?
От: Аноним  
Дата: 08.09.06 05:06
Оценка:
Какой из вариантов прeдпочтительнее?

Вариант 1.
class metal_safe_for_x_variable{
 private:
  int x;
 public:
   metal_safe_for_x_variable(int x_): x(x_) {}
}



Вариант 2.
class metal_safe_for_x_variable{
 private:
  int x;
 public:
   metal_safe_for_x_variable(int x_){x=x_;}
}


И самое главное ответ обосновать.
Re: какой код эффективнее?
От: CiViLiS Россия  
Дата: 08.09.06 05:16
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Какой из вариантов прeдпочтительнее?

В данном случае все пофигу. А вот если x -- user-defined тип, то второй пример проигрывает из-за лишнего вызова конструктора по умолчанию.
... << RSDN@Home 1.2.0 alpha rev. 655>>
"Бог не терпит голой сингулярности" -- Роджер Пенроуз
Re: какой код эффективнее?
От: ZverX Россия  
Дата: 08.09.06 05:26
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Какой из вариантов прeдпочтительнее?


А>Вариант 1.

А>
А>class metal_safe_for_x_variable{
А> private:
А>  int x;
А> public:
А>   metal_safe_for_x_variable(int x_): x(x_) {}
А>}
А>



А>Вариант 2.

А>
А>class metal_safe_for_x_variable{
А> private:
А>  int x;
А> public:
А>   metal_safe_for_x_variable(int x_){x=x_;}
А>}
А>


А>И самое главное ответ обосновать.



(Ехидно) Наверно тест домой дали?

Набросал пример на VC71
компилил Release без оптимизация


class metal_safe_for_x_variable1
{
  private:
    int x;
  public:
    metal_safe_for_x_variable1(int x_): x(x_) {}
};

class metal_safe_for_x_variable2{
  private:
    int x;
  public:
    metal_safe_for_x_variable2(int x_){x=x_;}
};

int _tmain(int argc, _TCHAR* argv[])
{

  DWORD c1 = GetTickCount();  
  for(int i=0; i < 100000000; ++i)
  {
    metal_safe_for_x_variable1 var(i);
  }
  DWORD c2 = GetTickCount();  

  std::cout << c2-c1 << std::endl;

  с1 = GetTickCount();  
  for(int i=0; i < 100000000; ++i)
  {
    metal_safe_for_x_variable2 var(i);
  }
  c2 = GetTickCount();  

  std::cout << c2-c1 << std::endl;
 
  std::cin.get();
}


Смотрим дизассемблер


metal_safe_for_x_variable1 var(i);
0040102A  mov         ecx,dword ptr [i] 
0040102D  push        ecx  
0040102E  lea         ecx,[var] 
00401031  call        std::locale::id::id (401070h) 


 metal_safe_for_x_variable2 var(i);
0040102A  mov         ecx,dword ptr [i] 
0040102D  push        ecx  
0040102E  lea         ecx,[var] 
00401031  call        std::locale::id::id (401070h)


хм, я то думал первый вариант быстрее — а оказалось одинаково...
Может кто меня поправит?
Re[2]: какой код эффективнее?
От: Аноним  
Дата: 08.09.06 05:51
Оценка:
Здравствуйте, CiViLiS, Вы писали:

CVL>Здравствуйте, <Аноним>, Вы писали:


А>>Какой из вариантов прeдпочтительнее?

CVL>В данном случае все пофигу. А вот если x -- user-defined тип, то второй пример проигрывает из-за лишнего вызова конструктора по умолчанию.

Не могу понять почему в случае классов лишний вызов конструктора?
Re[3]: какой код эффективнее?
От: CiViLiS Россия  
Дата: 08.09.06 06:20
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Не могу понять почему в случае классов лишний вызов конструктора?

Могу предложить поэксперементировать вот с этим примером:
struct A
{
  A()
    {
     i = -15;
       std::cout << __FUNCTION__ << std::endl;
    }
    int i;
}

struct B
{
   A a;
   B() 
     {  // <- вот здесь инициализируются все поля класса B. То есть вызывается A::A(). 
       std::cout << i << std::endl;
        a.i = 10; // а здесь уже не инициализация, а изменение.
       std::cout << i << std::endl;
     }
}

B b;

Программа выведет

A::A
-15
10


А если немного изменить класс A -- убрать дефолтный конструктор, то есть конструктор без параметров:
struct A
{
  A(int q)
    {
     i = q;
       std::cout << __FUNCTION__ << std::endl;
    }
    int i;
}


то компилятор на ругнется в конструкторе B():

error C2512: 'A' : no appropriate default constructor available


За подробностями лучше почитать Липпмана или Страуструпа. К сожалению сейчас ни того ни другого под рукой нету, поэтому цитаты не приведу. Зато естб стандарт, но там искать влом
... << RSDN@Home 1.2.0 alpha rev. 655>>
"Бог не терпит голой сингулярности" -- Роджер Пенроуз
Re[3]: какой код эффективнее?
От: Bell Россия  
Дата: 08.09.06 06:37
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, CiViLiS, Вы писали:


CVL>>Здравствуйте, <Аноним>, Вы писали:


А>>>Какой из вариантов прeдпочтительнее?

CVL>>В данном случае все пофигу. А вот если x -- user-defined тип, то второй пример проигрывает из-за лишнего вызова конструктора по умолчанию.

А>Не могу понять почему в случае классов лишний вызов конструктора?

При конструировании объекта класса сначала конструируются его базовые подобъекты, затем члены, затем исполняется тело конструктора. В варианте 1 в списке инициализации член x инициализируется с помощью конструктора с параметром, а тело конструктора metal_safe_for_x_variable пусто. В варианте 2 член x инициализируется с помощью конструктора по умолчанию, затем выполняется тело metal_safe_for_x_variable, в котором есть еще одно присваивание.
В общем случае вариант 1 эффективнее.

Пример:

class Int
{
   int i_;
public:
   Int() : i_(0) { cout << "Int def. ctor\n"; }
   Int(int i) : i_(i) { cout << "Int ctor\n"; }
   Int(const Int& i) : i_(i.i_) { cout << "Int copy ctor\n"; }
   Int& operator=(int i) { i_ = i; cout << "Int operator=\n"; return *this; }
};

class metal_safe_for_x_variable1{
 private:
  Int x_;
 public:
   metal_safe_for_x_variable1(int x) : x_(x) {}
};

class metal_safe_for_x_variable2{
 private:
  Int x_;
 public:
   metal_safe_for_x_variable2(int x) {x_ = x; }
};


int main()
{
    metal_safe_for_x_variable1 v1(1);
    cout << "----------------------\n";
    metal_safe_for_x_variable2 v2(2);

    return 0;
}


ЗЫ
Все это можно прочитать в любом приличном учебнике по С++.
Любите книгу — источник знаний (с) М.Горький
Re[3]: какой код эффективнее?
От: pastey  
Дата: 08.09.06 06:56
Оценка: +1
Здравствуйте, Аноним, Вы писали:

CVL>>В данном случае все пофигу. А вот если x -- user-defined тип, то второй пример проигрывает из-за лишнего вызова конструктора по умолчанию.


А>Не могу понять почему в случае классов лишний вызов конструктора?


Вариант 2.
class metal_safe_for_x_variable{
 private:
  int x;
 public:
   metal_safe_for_x_variable(int x_){x=x_;}
}


Перед вызовом конструктора класса, т.е. перед его открывающей скобкой '{', происходит создание всех внутренних элементов класса, и твоего 'x'- тоже (для него вызывается конструктор по-умолчанию). Затем при входе в конструктор создается локальная копия 'x_'(вызов констуктора копирования). И наконец x=x_; копирует содержимое x_ в твой x.

В Варианте 2. перед открывающей скобкой конструктора ты сам вызываешь сразу конструктор копирования для 'x', т.е. в принципе экономишь ты только на пропуске операции x=x_;,
т.к. при входе в конструктор опять таки создается локальная копия x_.

Лучший вариант — передать параметр 'x_' по ссылке, и перед скобкой сделать вызов конструктора копирования. В этом случае ты получаешь всего один вызов конструктора копирования, который выполняет как раз то, что тебе нужно — инициализирует 'x' содержимым 'x_'; и ни каких тебе созданий локальных переменных

class metal_safe_for_x_variable{
 private:
  x_class x;
 public:
   metal_safe_for_x_variable(x_class& x_):x(x_){}
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.