Re[2]: TOP граблей С++ для новичков
От: MasterZiv СССР  
Дата: 18.09.12 18:54
Оценка: 2 (2) +1
> ШЕ>Сейчас приходится собеседовать много новичков.
>
> Вам слишком рано ещё кого-то собеседовать.

Ребята, вот зачем вот это вот всё ?
В форумах по линуксу линуксоиды сруца, какой дистр лучше.
В форумах по плюсам -- кто плюсы знает лучше ...
Может лучше на неправ(иль|ослав)ные технологии свой гнев обращать
хоть когда-нибудь?
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Resource Acquisition Is Initialization
От: VladFein США  
Дата: 18.09.12 20:05
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>
ШЕ>void foo()
ШЕ>{
ШЕ>    FILE* f=fopen("data.txt","rb");
ШЕ>    file_hldr fh(f);//С этого момента, чтобы не случилось для f будет вызван fclose()
ШЕ>    ...
ШЕ>}
ШЕ>


Разве это пример RAII?
Вот если бы Ваш file_hldr сам открывал файл...
Re[3]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 18.09.12 21:23
Оценка:
Здравствуйте, VladFein, Вы писали:

ШЕ>>
ШЕ>>void foo()
ШЕ>>{
ШЕ>>    FILE* f=fopen("data.txt","rb");
ШЕ>>    file_hldr fh(f);//С этого момента, чтобы не случилось для f будет вызван fclose()
ШЕ>>    ...
ШЕ>>}
ШЕ>>


VF>Разве это пример RAII?

VF>Вот если бы Ваш file_hldr сам открывал файл...

То есть я так понимаю такой код ни есть RAII:

int main() {
  FILE *f; ptrdtor UNIQNAME( f = fopen("1.c","r"), call_ifn0(fclose) );
  printf("file: %p",f);
  //...
}
Re[4]: Resource Acquisition Is Initialization
От: VladFein США  
Дата: 18.09.12 21:38
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>То есть я так понимаю такой код ни есть RAII:


AS>
AS>int main() {
AS>  FILE *f; ptrdtor UNIQNAME( f = fopen("1.c","r"), call_ifn0(fclose) );
AS>  printf("file: %p",f);
AS>  //...
AS>} 
AS>


Что такое ptrdtor? UNIQNAME? call_ifn0?
Re[5]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 22:07
Оценка:
Здравствуйте, VladFein, Вы писали:

AS>>То есть я так понимаю такой код ни есть RAII:

AS>>
AS>>int main() {
AS>>  FILE *f; ptrdtor UNIQNAME( f = fopen("1.c","r"), call_ifn0(fclose) );
AS>>  printf("file: %p",f);
AS>>  //...
AS>>} 
AS>>

VF>Что такое ptrdtor? UNIQNAME? call_ifn0?

ну, судя по использованию:
ptrdtor — что-то типа scoped_ptr, но хранящий "deleter"
UNIQNAME — макрос раскрывающийся в типа уникальный идентификатор.
call_ifn0 — унарный функтор, сравнивающий в operator() аргумент на 0, и если не ноль то вызывает функтор переданный в конструкторе с этим аргументом.
Re[5]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 18.09.12 22:40
Оценка:
VF>Что такое ptrdtor? UNIQNAME? call_ifn0?

А что, знание реализации как-то меняет семантику RAII? Впрочем, ИМХО всё более чем очевидно:
#include <memory>

template <class T,class R> struct call_ifn0_t { 
  R (*f)(T); 
  void operator()(T t) { if ( t ) f(t); } 
};

template <class T,class R> call_ifn0_t<T,R> call_ifn0(R(*f)(T)) { 
  call_ifn0_t<T,R> q = { f }; 
  return q; 
}

typedef std::shared_ptr<void> ptrdtor;
#define MACRO_CONCAT1(a,b) a##b
#define MACRO_CONCAT(a,b) MACRO_CONCAT1(a,b) 
#define UNIQNAME MACRO_CONCAT(local_uniqname_at_line_,__LINE__)
Re[6]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 22:55
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>ptrdtor UNIQNAME(...);

и
AS>typedef std::shared_ptr<void> ptrdtor;

это как пушкой по воробьям. он же thread-safe ref-count
Re[6]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 22:58
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>
AS>template <class T,class R> call_ifn0_t<T,R> call_ifn0(R(*f)(T)) { 
AS>  call_ifn0_t<T,R> q = { f }; 
AS>  return q; 
AS>}
AS>


да, и зачем nrvo, а не?
тем более в C++11 можно так:
template <class T,class R> call_ifn0_t<T,R> call_ifn0(R(*f)(T)) { 
  return { f }; 
}
Re[7]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 22:58
Оценка:
P>да, и зачем nrvo, а не?
а не rvo
Re[7]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 18.09.12 23:08
Оценка: -2
AS>>ptrdtor UNIQNAME(...);
AS>>typedef std::shared_ptr<void> ptrdtor;
P>это как пушкой по воробьям. он же thread-safe ref-count

Э... вопрос то как бы про другое был )
Работает? — Да. RAII? — Тоже да. Просто? — вроде как более чем.
Коротко и понятно без реализации? — ... ну ты же понял.

P>тем более в C++11 можно так


Ну, классно да. Десятая студия прожуёт? )
Re[8]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 23:26
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>Э... вопрос то как бы про другое был )


не спорю

P>>тем более в C++11 можно так

AS>Ну, классно да. Десятая студия прожуёт? )

десятая давится, одиннадцатая — давится, gcc-4.5.1 — жуёт.
с одиннадцатой вообще прикол, она на fclose выдаёт, ошибку компиляции, по дефолту! всё, приплыли

Error 1 error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.


в любом случае, для чего там локальная переменная, а не просто return? или это без смысловой нагрузки?
Re[9]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 23:28
Оценка:
Здравствуйте, Piko, Вы писали:

P>с одиннадцатой вообще прикол, она на fclose выдаёт, ошибку компиляции, по дефолту! всё, приплыли


не, сорри, мой косяк, кинул не в тот проект.. у меня просто по умолчанию варниги до ошибок аппятся
Re[9]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 18.09.12 23:45
Оценка:
P>в любом случае, для чего там локальная переменная, а не просто return? или это без смысловой нагрузки?

Ну вообще-то простейший способ вернуть структуру, совместимый со всем что движется. Можно конечно конструктор написать ... но зачем? Код в результате всё равно один и тот же будет — записать в rax указатель и выйти из функции. Хотя итоге оно таки заинлайнится и выродится в передачу результата fopen и адреса fclose в конструктор.
Re[10]: Resource Acquisition Is Initialization
От: Piko  
Дата: 18.09.12 23:54
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

AS>Ну вообще-то простейший способ вернуть структуру, совместимый со всем что движется. Можно конечно конструктор написать ... но зачем? Код в результате всё равно один и тот же будет — записать в rax указатель и выйти из функции. Хотя итоге оно таки заинлайнится и выродится в передачу результата fopen и адреса fclose в конструктор.


может в этом конкретном случае и заинлайнится. но, вот тот же msvc nrvo не делает в debug, а rvo делает.
да, и к чему тут rax? он вообще может не использоваться, так как nrvo/rvo. ну да ладно..
Re[11]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 19.09.12 00:19
Оценка:
P>может в этом конкретном случае и заинлайнится. но, вот тот же msvc nrvo не делает в debug, а rvo делает.
Какая разница? Это просто указатель. Мало ли как он представлен и во что завёрнут.

P>да, и к чему тут rax? он вообще может не использоваться, так как nrvo/rvo. ну да ладно..

Э... покажи мне сгенерированный код, возвращающий указатель без использования rax.

gcc / return { f };
cl / return q;

gcc -O0
leaq    fclose(%rip), %rcx
call    _Z9call_ifn0IP6_iobufiE11call_ifn0_tIT_T0_EPFS4_S3_E
movq    %rax, 24(%rbp)


cl -Od
push     OFFSET _fclose
call     ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add     esp, 4
mov     DWORD PTR $T65617[ebp], eax


gcc -O2, __attribute__((noinline))
leaq    fclose(%rip), %rcx
call    _Z9call_ifn0IP6_iobufiE11call_ifn0_tIT_T0_EPFS4_S3_E
movq    %rax, 152(%rsp)

_Z9call_ifn0IP6_iobufiE11call_ifn0_tIT_T0_EPFS4_S3_E:
movq    %rcx, %rax
ret


cl -O2, __declspec(noinline)
push     OFFSET _fclose
call     ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
mov     edi, eax

??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z PROC ;
mov     eax, DWORD PTR _f$[esp-4]
ret      0


Чёт не вижу принципиальной разницы.
Re[12]: Resource Acquisition Is Initialization
От: Piko  
Дата: 19.09.12 01:00
Оценка:
Здравствуйте, Alexéy Sudachén, Вы писали:

P>>да, и к чему тут rax? он вообще может не использоваться, так как nrvo/rvo. ну да ладно..

AS>Э... покажи мне сгенерированный код, возвращающий указатель без использования rax.

при rvo/nrvo в функцию передаётся скрытая ссылка, на то, куда писать результат. я предполагал, что в этом случае eax не заполняется. но видимо так оптимальней — чтобы лишний раз не высчитывать.

вот rvo, msvc2010 debug:
mov    eax, DWORD PTR __imp__fclose
push    eax
lea    ecx, DWORD PTR $T20367[ebp]
push    ecx
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 8
mov    edx, DWORD PTR [eax]
push    edx
call    ??$some@U?$call_ifn0_t@PAU_iobuf@@H@@@@YAXU?$call_ifn0_t@PAU_iobuf@@H@@@Z ; some<call_ifn0_t<_iobuf *,int> >

причём тут ecx перед call, который пушится, равен eax после возврата.

а вот отсутствие nrvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 4
mov    DWORD PTR $T20358[ebp], eax
mov    ecx, DWORD PTR $T20358[ebp]
push    ecx
call    ??$some@U?$call_ifn0_t@PAU_iobuf@@H@@@@YAXU?$call_ifn0_t@PAU_iobuf@@H@@@Z ; some<call_ifn0_t<_iobuf *,int> >


то есть eax таки используется. но в случае rvo не из-за нужды, а для оптимальности.
Re[13]: Resource Acquisition Is Initialization
От: Piko  
Дата: 19.09.12 01:10
Оценка:
Здравствуйте, Piko, Вы писали:

P>то есть eax таки используется. но в случае rvo не из-за нужды, а для оптимальности.


ещё:
int main()
{
    auto temp=call_ifn0(fclose);
    printf("");
}


rvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
lea    ecx, DWORD PTR _temp$[ebp]
push    ecx
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 8
; Line 27
mov    esi, esp
push    OFFSET $SG19940
call    DWORD PTR __imp__printf

eax тут вообще не используется

отсутсвие nrvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 4
mov    DWORD PTR $T20360[ebp], eax
mov    ecx, DWORD PTR $T20360[ebp]
mov    DWORD PTR _temp$[ebp], ecx
; Line 27
mov    esi, esp
push    OFFSET $SG19935
call    DWORD PTR __imp__printf


причём была бы там структура побольше, было бы наглядней:
rvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
lea    ecx, DWORD PTR _temp$[ebp]
push    ecx
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 8
; Line 28
mov    esi, esp
push    OFFSET $SG19942
call    DWORD PTR __imp__printf


отсутствие nrvo:
mov    eax, DWORD PTR __imp__fclose
push    eax
lea    ecx, DWORD PTR $T20363[ebp]
push    ecx
call    ??$call_ifn0@PAU_iobuf@@H@@YA?AU?$call_ifn0_t@PAU_iobuf@@H@@P6AHPAU_iobuf@@@Z@Z ; call_ifn0<_iobuf *,int>
add    esp, 8
mov    edx, DWORD PTR [eax]
mov    DWORD PTR $T19931[ebp], edx
mov    ecx, DWORD PTR [eax+4]
mov    DWORD PTR $T19931[ebp+4], ecx
mov    edx, DWORD PTR [eax+8]
mov    DWORD PTR $T19931[ebp+8], edx
mov    ecx, DWORD PTR [eax+12]
mov    DWORD PTR $T19931[ebp+12], ecx
mov    edx, DWORD PTR [eax+16]
mov    DWORD PTR $T19931[ebp+16], edx
mov    eax, DWORD PTR [eax+20]
mov    DWORD PTR $T19931[ebp+20], eax
mov    ecx, DWORD PTR $T19931[ebp]
mov    DWORD PTR _temp$[ebp], ecx
mov    edx, DWORD PTR $T19931[ebp+4]
mov    DWORD PTR _temp$[ebp+4], edx
mov    eax, DWORD PTR $T19931[ebp+8]
mov    DWORD PTR _temp$[ebp+8], eax
mov    ecx, DWORD PTR $T19931[ebp+12]
mov    DWORD PTR _temp$[ebp+12], ecx
mov    edx, DWORD PTR $T19931[ebp+16]
mov    DWORD PTR _temp$[ebp+16], edx
mov    eax, DWORD PTR $T19931[ebp+20]
mov    DWORD PTR _temp$[ebp+20], eax
; Line 28
mov    esi, esp
push    OFFSET $SG19937
call    DWORD PTR __imp__printf
Re[13]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 19.09.12 01:59
Оценка:
P>при rvo/nrvo в функцию передаётся скрытая ссылка, на то, куда писать результат. я предполагал, что в этом случае eax не заполняется. но видимо так оптимальней — чтобы лишний раз не высчитывать.
P>то есть eax таки используется. но в случае rvo не из-за нужды, а для оптимальности.

Таки получается что чутьё меня не подвело, а CL откровенно тупит. Получается что я был о нём лучшего мнения. Ну и нафиг нужен такой RVO?

#include <stdio.h>

struct A {
  void *f;
  void operator()() { printf("%p\n",f); }
};

A __declspec(noinline) g(void *p) {
  A a = { p };
  return a;
}

struct B {
  void *f;
  B(void *ff) : f(ff) {}
  void operator()() { printf("%p\n",f); }
};

B __declspec(noinline) gg(void *p) {
  return B(p);
}

int main()
 {
   A a = g((void*)1);
   B b = gg((void*)2);
   a();
   b();
 }


cl -O2 1.cpp -FAsc

; 25   :    A a = g((void*)1);
  00000    51         push     ecx

; 25   :    A a = g((void*)1);

  00001    6a 01         push     1
  00003    e8 00 00 00 00     call     ?g@@YA?AUA@@PAX@Z    ; g
  00008    8b d0         mov     edx, eax

; 26   :    B b = gg((void*)2);

  0000a    8d 44 24 04     lea     eax, DWORD PTR _b$[esp+8]
  0000e    6a 02         push     2
  00010    50         push     eax
  00011    e8 00 00 00 00     call     ?gg@@YA?AUB@@PAX@Z    ; gg

; 27   :    a();

  00016    52         push     edx
  00017    68 00 00 00 00     push     OFFSET ??_C@_03OHEJPPDF@?$CFp?6?$AA@
  0001c    e8 00 00 00 00     call     _printf

; 28   :    b();

  00021    8b 4c 24 14     mov     ecx, DWORD PTR _b$[esp+24]
  00025    51         push     ecx
  00026    68 00 00 00 00     push     OFFSET ??_C@_03OHEJPPDF@?$CFp?6?$AA@
  0002b    e8 00 00 00 00     call     _printf
Re[14]: Resource Acquisition Is Initialization
От: Alexéy Sudachén Чили  
Дата: 19.09.12 02:20
Оценка:
P>причём была бы там структура побольше, было бы наглядней:

а что давай сделаем побольше )))

#include <stdio.h>

struct A {
  void *f;
  void *q;
  void operator()() { printf("%p,%p\n",f,q); }
};

A __declspec(noinline) g(void *p) {
  A a = { p };
  return a;
}

struct B {
  void *f;
  void *q;
  B(void *ff) : f(ff), q(0) {}
  void operator()() { printf("%p,%p\n",f,q); }
};

B __declspec(noinline) gg(void *p) {
  return B(p);
}

int main()
 {
   A a = g((void*)1);
   B b = gg((void*)2);
   a();
   b();
 }


cl -O2 -FAs 1.cpp

?g@@YA?AUA@@PAX@Z PROC                    ; g, COMDAT
; 11   :   A a = { p };
    mov    eax, DWORD PTR _p$[esp-4]
    xor    edx, edx
; 12   :   return a;
    ret    0

?gg@@YA?AUB@@PAX@Z PROC                    ; gg, COMDAT
; 23   :   return B(p);
    mov    eax, DWORD PTR ___$ReturnUdt$[esp-4]
    mov    ecx, DWORD PTR _p$[esp-4]
    mov    DWORD PTR [eax], ecx
    mov    DWORD PTR [eax+4], 0
    ret    0

_main    PROC                        ; COMDAT
; 27   :  {
    sub    esp, 8
    push    esi
; 28   :    A a = g((void*)1);
    push    1
    call    ?g@@YA?AUA@@PAX@Z            ; g
    mov    esi, eax
; 29   :    B b = gg((void*)2);
    lea    eax, DWORD PTR _b$[esp+16]
    push    2
    push    eax
    call    ?gg@@YA?AUB@@PAX@Z            ; gg
; 30   :    a();
    push    edx
    push    esi
    push    OFFSET ??_C@_06MJPHCGKI@?$CFp?0?$CFp?6?$AA@
    call    _printf
; 31   :    b();
    mov    ecx, DWORD PTR _b$[esp+40]
    mov    edx, DWORD PTR _b$[esp+36]
    push    ecx
    push    edx
    push    OFFSET ??_C@_06MJPHCGKI@?$CFp?0?$CFp?6?$AA@
    call    _printf
    add    esp, 36                    ; 00000024H
; 32   :  }


Действительно нагляднее. Однако у студии серьёзные проблемы с пессимизацией оптимизации возвращаемого значения. Gcc этим не страдает.
Re[2]: Копирующий конструктор и копирующий operator= по умолчанию.
От: Centaur Россия  
Дата: 19.09.12 04:23
Оценка:
Здравствуйте, Шебеко Евгений, Вы писали:

ШЕ>Если класс не содержит явного копирующего конструктора или operator=, то они создаются неявно.

ШЕ>Об этом надо помнить.

Каноническая формулировка называется Law of the Big Three: «если в вашем классе понадобилось явно определить деструктор, копирующий конструктор или оператор присваивания, скорее всего вам нужны все три».
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.