43 | 1.3.1. |
73 | 2.5.5. |
79 | 2.7.2. |
128 | 5.1.1. |
192 | 7.4. |
199 | 7.6. |
202 | 7.7. |
296 | 10.4.6.2. - |
297 | 10.4.7. |
316 | 11.3.1. - - |
328 | 11.5.1. |
333 | 11.7.1. |
337 | 11.9. |
344 | 11.12. String |
351 | 12.2. |
361 | 12.2.6. |
382 | 13.2.3. |
399 | 13.6.2. - |
419 | 14.4.1. |
421 | 14.4.2. auto_ptr |
422 | 14.4.4. new |
431 | 14.6.1. |
431 | 14.6.3. |
460 | 15.3.2. |
461 | 15.3.2.1. |
475 | 15.5. |
477 | 15.6. |
478 | 15.6. |
479 | 15.6.1. |
480 | 15.6.2. " " |
498 | 16.2.3. STL- |
505 | 16.3.4. |
508 | 16.3.5. |
526 | 17.1.4.1. |
541 | 17.4.1.2. |
543 | 17.4.1.3. |
555 | 17.5.3.3. |
556 | 17.6. |
583 | 18.4.4.1. |
584 | 18.4.4.2. - |
592 | 18.6. , |
592 | 18.6.1. |
622 | 19.2.5. |
634 | 19.4.1. |
637 | 19.4.2. , |
641 | 19.4.4. |
647 | 20.2.1. |
652 | 20.3.4. |
655 | 20.3.6. |
676 | 21.2.2. |
687 | 21.3.4. |
701 | 21.4.6.3. , |
711 | 21.6.2. |
773 | 23.4.3.1. 1: |
879 | .5. |
931 | B.13.2. |
935 | B.13.6. template |
( ) C++ 3rd , , . - , , .
. , " C++" , .. , C++. C++ 3rd, C++. , () , , .
- , : Bjarne Stroustrup "The C++ Programming language", 3rd edition / C++ (ISO/IEC 14882 Programming languages - C++, First edition, 1998-09-01). , , C++ . , , C++ Standard Core Issues List C++ Standard Library Issues List .
STL, . , , .
, "The C programming Language" by Brian W. Kernighan and Dennis M. Ritchie, 2 , -- !
, .
new
, delete
, type_id
, dynamic_cast
, throw
try
, C++ .
, , " ". / () , / , / , , .
#include <stdio.h> #include <stdlib.h> #include <time.h> struct A { A(); ~A(); }; void ACon(); void ADes(); void f1() { A a; } void f2() { ACon(); ADes(); } long Var, Count; A::A() { Var++; } A::~A() { Var++; } void ACon() { Var++; } void ADes() { Var++; } int main(int argc,char** argv) { if (argc>1) Count=atol(argv[1]); clock_t c1,c2; { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000000; j++) f1(); c2=clock(); printf("f1(): %ld mlns calls per %.1f sec\n",Count,double(c2-c1)/CLK_TCK); } { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000000; j++) f2(); c2=clock(); printf("f2(): %ld mlns calls per %.1f sec\n",Count,double(c2-c1)/CLK_TCK); } }
f1()
f2()
, , A
, ACon()
ADes()
.
-- . , f1()
f2()
.
; , 10 !
inline
? :
struct A { A() { Var++; } ~A() { Var++; } }; void f1() { A a; } void f2() { Var++; Var++; }
f1()
f2()
. , .
? abstraction penalty, .. (-) .
abstraction penalty .
void f1() { A a; }
void f1() // { A::A(); A::~A(); }:
void f2() { ACon(); ADes(); }-- ! , :
void f1() { A a; f(); } void f2() { ACon(); f(); ADes(); }, ? -- , ..
f1()
void f1() // { A::A(); try { f(); } catch (...) { A::~A(); throw; } A::~A(); }.. , , . .. , , .
f1()
(, "" /):
void f1() // { A::A(); try { // } catch (...) { A::~A(); throw; } A::~A(); }, , " ", . ,
inline
. STL, , , .
abstraction penalty -- " ".
vtbl
.
, .. "" vtbl
.
. (.. ) B1
:
struct B1 { // struct int a1; int b1; virtual ~B1() { } };
vptr
( ) . B1
:
vptr_1 // vtbl B1 a1 // b1
B2
D
struct D: B1, B2 { virtual ~D() { } };:
vptr_d1 // vtbl D, B1 vptr_1 a1 // B1 b1 vptr_d2 // vtbl D, B2 vptr_2 a2 // B2 b2
vptr
? , , .
, , , : " "? , . , . .. :
D d; B2* ptr=&d;
ptr
vptr_d2
. vptr
D
vptr_d1
. , , . ? B1
B2
vtbl
, D
. .. vtbl
D
: B1
, B2
.
, , , .
, , , : vptr
this
vtbl
. , .
, .
#include <stdio.h> #include <stdlib.h> #include <time.h> struct B { void f(); virtual void vf(); }; struct D : B { void vf(); // B::vf }; void f1(B* ptr) { ptr->f(); } void f2(B* ptr) { ptr->vf(); } long Var, Count; void B::f() { Var++; } void B::vf() { } void D::vf() { Var++; } int main(int argc,char** argv) { if (argc>1) Count=atol(argv[1]); clock_t c1,c2; D d; { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000000; j++) f1(&d); c2=clock(); printf("f1(): %ld mlns calls per %.1f sec\n",Count,double(c2-c1)/CLK_TCK); } { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000000; j++) f2(&d); c2=clock(); printf("f2(): %ld mlns calls per %.1f sec\n",Count,double(c2-c1)/CLK_TCK); } }, 10% 2.5 . .. , "" .
"" , .. ( )
#include <stdio.h> #include <stdlib.h> #include <time.h> struct B { int ackf(int x, int y); virtual int vackf(int x, int y); }; struct D : B { int vackf(int x, int y); // B::vackf }; void f1(B* ptr) { ptr->ackf(3, 5); // 42438 ! } void f2(B* ptr) { ptr->vackf(3, 5); // 42438 ! } int B::ackf(int x, int y) { if (x==0) return y+1; else if (y==0) return ackf(x-1, 1); else return ackf(x-1, ackf(x, y-1)); } int B::vackf(int x, int y) { return 0; } int D::vackf(int x, int y) { if (x==0) return y+1; else if (y==0) return vackf(x-1, 1); else return vackf(x-1, vackf(x, y-1)); } long Count; int main(int argc,char** argv) { if (argc>1) Count=atol(argv[1]); clock_t c1,c2; D d; { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000; j++) f1(&d); c2=clock(); printf("f1(): %ld ths calls per %.1f sec\n", Count, double(c2-c1)/CLK_TCK); } { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000; j++) f2(&d); c2=clock(); printf("f2(): %ld ths calls per %.1f sec\n", Count, double(c2-c1)/CLK_TCK); } }, .
char vc1[200]; char vc2[500]; void f() { copy(&vc1[0],&vc1[200],&vc2[0]); }
, , . - :
The issue is whether taking the address of one-past-the-last element of an array is conforming C and C++. I could make the example clearly conforming by a simple rewrite:copy(vc1,vc1+200,vc2);However, I don't want to introduce addition to pointers at this point of the book. It is a surprise to most experienced C and C++ programmers that&vc1[200]
isn't completely equivalent tovc1+200
. In fact, it was a surprise to the C committee also and I expect it to be fixed in the upcoming revision of the standard. (also resolved for C9x - bs 10/13/98)., C C++ , . :
copy(vc1,vc1+200,vc2);, . C C++ ,&vc1[200]
vc1+200
. , C , , .
? C++ :
&vc1[200] -> &(*((vc1)+(200))) -> &*(vc1+200)
&*(vc1+200) == vc1+200
?
It is false in C89 and C++, but not in K&R C or C9x. The C89 standard simply said that&*(vc1+200)
means dereferencevc1+200
(which is an error) and then take the address of the result, and the C++ standard copiled the C89 wording. K&R C and C9x say that&*
cancels out so that&*(vc1+200) == vc2+200
.89 C++, K&R C 9. 89 ,
&*(vc1+200)
vc1+200
( ) . C++ 89. K&R C 9 ,&*
, ..&*(vc1+200) == vc1+200
.
, &*(vc1+200)
*(vc1+200)
, .. ( ) &
.
NULL
,
const int NULL=0;
, , ( ) NULL
, 0
-- .
, NULL
static_cast<SomeType*>(0)
.
, , NULL
. , :
#include <stdio.h> #include <stdarg.h> #include <stdlib.h> void error(int stat ...) { va_list ap; va_start(ap, stat); while (const char* sarg=va_arg(ap, const char *)) printf("%s", sarg); va_end(ap); exit(stat); } int main() { error(1, " ", "", NULL); // , ! // NULL // static_cast<const char *>(0) }(, )
NULL
0L
( 0
) , sizeof(void*)==sizeof(long)>sizeof(int)
.
[2] :
bool
int
, char
int
, short
int;
B.6.1), float
double
.
struct A { private: void f(int); public: void f(...); }; void g() { A a; a.f(1); // : A::f(int), // g() }, : - .
va_start()
, va_end()
. , va_start()
, .
.
, . , , .
, va_end()
. , / C++ , .. "" std::cout
va_end()
.
cmp3
ssort()
, ssort()
mytype*
.
, . : , cmp3
ssort()
, cmp3()
mytype*
.
, ? ? - :
The reason for "discriminating against" floating points in constant expressions is that the precision of floating point traditionally varied radically between processors. In principle, constant expressions should be evaluated on the target processor if you are cross compiling."" , . , -, .
.. - , ( ) .
, - (, , ) , ..
class Curious { static const float c5=7.0; };() .
, . , :
#include <stdio.h> struct A { // int a; A(int a_) : a(a_) { printf("%d\n",a); } }; void f() { static int vals[]={2, 0, 0, 4}; static int curr=0; struct A_local : public A { // A_local() : A(vals[curr++]) { } }; A_local arr[4]; // A arr[4]; } int main() { f(); }.. , :
9.8 [class.local]
int x; void f() { static int s; int x; extern int g(); struct local { int g() { return x; } // , auto x int h() { return s; } // OK int k() { return ::x; } // OK int l() { return g(); } // OK }; // ... } local* p = 0; // : local
Y
X
X
, (scope), X
. .
complex r1=x+y+z; // r1=operator+(x,operator+(y,z))
:
complex r1=x+y+z; // r1=operator+(operator+(x,y),z):
(x+y)+z
.
// f() class X { friend void f(); // friend void h(const X&); // }; void g(const X& x) { f(); // f() h(x); // h() -- X }8- ,
f
, - f()
X
f
, f()
g()
.
String s1='a'; // : char String String s2(10); // : 10...
. .
X a=b;
a
X
X
. :
b
X
. :
X a(b);
b
X
. X
, :
X a(X(b));explicit-, .
12.8 [class.copy]
return
, ( cv-) , , . , , .
#include <stdio.h> #include <string.h> struct A { static const int nsize=10; char n[nsize]; A(char cn) { n[0]=cn; n[1]=0; printf("%5s.A::A()\n", n); } A(const A& a) { if (strlen(a.n)<=nsize-2) { n[0]='?'; strcpy(n+1, a.n); } else strcpy(n, ""); printf("%5s.A::A(const A& %s)\n", n, a.n); } ~A() { printf("%5s.A::~A()\n", n); } A& operator=(const A& a) { if (strlen(a.n)<=nsize-2) { n[0]='='; strcpy(n+1, a.n); } else strcpy(n, ""); printf("%5s.A::operator=(const A& %s)\n", n, a.n); return *this; } }; A f1(A a) { printf("A f1(A %s)\n", a.n); return a; } A f2() { printf("A f2()\n"); A b('b'); return b; } A f3() { printf("A f3()\n"); return A('c'); } int main() { { A a('a'); A b='b'; A c(A('c')); A d=A('d'); } printf("----------\n"); { A a('a'); A b=f1(a); printf("b %s\n", b.n); } printf("----------\n"); { A a=f2(); printf("a %s\n", a.n); } printf("----------\n"); { A a=f3(); printf("a %s\n", a.n); } },
main()
a
, b
, c
d
. :
a.A::A() b.A::A() c.A::A() d.A::A() d.A::~A() c.A::~A() b.A::~A() a.A::~A(), , , :
... c.A::A() ?c.A::A(const A& c) c.A::~A() d.A::A() d.A::~A() ?c.A::~A() .....
A c(A('c'))
A tmp('c'), c(tmp)
. , f1()
:
a.A::A() ?a.A::A(const A& a) A f1(A ?a) ??a.A::A(const A& ?a) ?a.A::~A() b ??a ??a.A::~A() a.A::~A()
a
?a
, f1()
. , f1()
?a
-- ??a
, . - : b ??a
, .. main()
b
-- , f1()
??a
, ( : , b ???a
).
-- , . f2()
f3()
:
A f2() b.A::A() ?b.A::A(const A& b) b.A::~A() a ?b ?b.A::~A() ---------- A f3() c.A::A() a c c.A::~A()
f3()
, f2()
-- ! , .
, .. ( !).
-- . :
#include <stdio.h> #include <string.h> struct A { static const int nsize=10; static int tmpcount; int val; char n[nsize]; A(int val_) : val(val_) // { sprintf(n, "_%d", ++tmpcount); printf("%5s.A::A(int %d)\n", n, val); } A(char cn, int val_) : val(val_) { n[0]=cn; n[1]=0; printf("%5s.A::A(char, int %d)\n", n, val); } A(const A& a) : val(a.val) { if (strlen(a.n)<=nsize-2) { n[0]='?'; strcpy(n+1, a.n); } else strcpy(n, ""); printf("%5s.A::A(const A& %s)\n", n, a.n); } ~A() { printf("%5s.A::~A()\n", n); } A& operator=(const A& a) { val=a.val; if (strlen(a.n)<=nsize-2) { n[0]='='; strcpy(n+1, a.n); } else strcpy(n, ""); printf("%5s.A::operator=(const A& %s)\n", n, a.n); return *this; } friend A operator+(const A& a1, const A& a2) { printf("operator+(const A& %s, const A& %s)\n", a1.n, a2.n); return A(a1.val+a2.val); } }; int A::tmpcount; int main() { A a('a', 1), b('b', 2), c('c', 3); A d=a+b+c; printf("d %s\n", d.n); printf("d.val=%d\n", d.val); }:
a.A::A(char,int 1) b.A::A(char,int 2) c.A::A(char,int 3) operator+(const A& a,const A& b) _1.A::A(int 3) operator+(const A& _1,const A& c) _2.A::A(int 6) _1.A::~A() d _2 d.val=6 _2.A::~A() c.A::~A() b.A::~A() a.A::~A(), .
A d('d',0); d=a+b+c;:
a.A::A(char,int 1) b.A::A(char,int 2) c.A::A(char,int 3) d.A::A(char,int 0) operator+(const A& a,const A& b) _1.A::A(int 3) operator+(const A& _1,const A& c) _2.A::A(int 6) =_2.A::operator=(const A& _2) _2.A::~A() _1.A::~A() d =_2 d.val=6 =_2.A::~A() c.A::~A() b.A::~A() a.A::~A()
operator()()
Add(z)
.
, : - , . .
, , - for_each()
template <class InputIter, class Function> Function for_each(InputIter first, InputIter last, Function f) { for ( ; first != last; ++first) f(*first); return f; }sgi STL ( ). , ( -) .
for_each()
c Add(z)
,
for_each(ll.begin(), ll.end(), Add(z));
Function
-- Add
, .. , Add(z)
. for_each()
:
Add for_each(InputIter first, InputIter last, Add f) { for ( ; first != last; ++first) f.operator()(*first); return f; }..
for_each()
Add(z)
, . , for_each()
Add::operator()(complex&)
. , InputIter
, .
? , -- -, . , ,
Add for_each(...) { for (...) Add(z).operator()(*first); return f; }, , , : , .
String
s.operator[](1)
Cref(s,1)
.
. const
const
-? ?
:
struct X { void f(int); void f(int) const; }; void h() { const X cx; cx.f(1); X x; x.f(2); }, -
this
,
// struct X { void f( X *const this); void f(const X *const this); }; void h() { const X cx; X::f(&cx,1); X x; X::f(&x,2); }. , .
, - . : , , , . .. , . - , , , ().
, , . " " . :
#include <stdio.h> struct B1 { int b1; // virtual ~B1() { } }; struct B2 { int b2; // virtual void vfun() { } }; struct D : B1, B2 { // virtual void vfun() { printf("D::vfun(): this=%p\n", this); } }; int main() { D d; D* dptr=&d; printf("dptr\t%p\n", dptr); dptr->vfun(); B2* b2ptr=&d; printf("b2ptr\t%p\n", b2ptr); b2ptr->vfun(); }:
dptr 0x283fee8 D::vfun(): this=0x283fee8 b2ptr 0x283feec D::vfun(): this=0x283fee8..
dptr
, D::vfun()
this=0x283fee8
. , () b2ptr
, () , D::vfun()
, D::vfun()
this
.
? ,
struct D : B1, B2 { virtual void vfun(D *const this) // { // ... } };
ptr->vfun()
(*vtbl[index_of_vfun])(ptr)
, b2ptr==0x283feec==this!=0x283fee8
.
: ? , (D::vfun()
) (ptr==0x283fee8
) (ptr==0x283feec
), , this
(this==0x283fee8
) .
, vtbl
, , , . , , :
vtbl
-- vdelta
. vtbl
, ptr
:
addr=vtbl[index].vaddr; // vfun delta=vtbl[index].vdelta; // , vfun (*addr)(ptr+delta); // vfun
vtbl
: , ptr
, vdelta
. -- ANSI C , C++ -> C .
ptr
( ):
vfun_entry_0: // ... // vfun // ... return; vfun_entry_1: ptr+=delta_1; // ptr goto vfun_entry_0; // vfun
vtbl
. ANSI C.
-- (internal linkage).
-... , . , :
Curiously enough, a template constructor is never used to generate a copy constructor, so without the explicitly declared copy constructor, a default copy constructor would have been generated., - , .. .
, " " "-".
, , , try/catch
, -- . -, ? :
#include <stdio.h> #include <stdlib.h> #include <time.h> void ResourceAcquire(); void ResourceRelease(); void Work(); struct RAII { RAII() { ResourceAcquire(); } ~RAII() { ResourceRelease(); } }; void f1() { ResourceAcquire(); try { Work(); } catch (...) { ResourceRelease(); throw; } ResourceRelease(); } void f2() { RAII raii; Work(); } long Var, Count; void ResourceAcquire() { Var++; } void ResourceRelease() { Var--; } void Work() { Var+=2; } int main(int argc, char** argv) { if (argc>1) Count=atol(argv[1]); clock_t c1, c2; { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000000; j++) f1(); c2=clock(); printf("f1(): %ld mln calls per %.1f sec\n", Count, double(c2-c1)/CLK_TCK); } { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000000; j++) f2(); c2=clock(); printf("f2(): %ld mln calls per %.1f sec\n", Count, double(c2-c1)/CLK_TCK); } }, ? !
f1()
, f2()
, - . .
? , -. ! , Structured Exception Handling / (multithreading). , ...
Internet exception handling (EH) C++ , . , EH C++ .
, " " , . , .. EH, (, , ) () (, (E)IP Intel-) .
(, , EH) , EH Control Flow Graph, .. , .
, EH 5%, .
! , "" -- : " "...
auto_ptr
<memory>
auto_ptr
...
, () auto_ptr
, ( 4 ).
( (destructive copy semantics)), auto_ptr
: auto_ptr
, auto_ptr
( 0
). .. auto_ptr
, const auto_ptr
.
auto_ptr
<memory>
:
template<class X> class std::auto_ptr { // template <class Y> struct auto_ptr_ref { /* ... */ }; X* ptr; public: typedef X element_type; explicit auto_ptr(X* p =0) throw() { ptr=p; } ~auto_ptr() throw() { delete ptr; } // : // // , a.ptr=0 auto_ptr(auto_ptr& a) throw(); // , a.ptr=0 template<class Y> auto_ptr(auto_ptr<Y>& a) throw(); // , a.ptr=0 auto_ptr& operator=(auto_ptr& a) throw(); // , a.ptr=0 template<class Y> auto_ptr& operator=(auto_ptr<Y>& a) throw(); X& operator*() const throw() { return *ptr; } X* operator->() const throw() { return ptr; } // X* get() const throw() { return ptr; } // X* release() throw() { X* t = ptr; ptr=0; return t; } void reset(X* p =0) throw() { if (p!=ptr) { delete ptr; ptr=p; } } // auto_ptr_ref auto_ptr(auto_ptr_ref<X>) throw(); // auto_ptr_ref template<class Y> operator auto_ptr_ref<Y>() throw(); // auto_ptr template<class Y> operator auto_ptr<Y>() throw(); };
auto_ptr_ref
-- , auto_ptr
. - - auto_ptr<D>
auto_ptr<B>
D*
B*
, :
void g(Circle* pc) { auto_ptr<Circle> p2 = pc; // p2 auto_ptr<Circle> p3 = p2; // p3 , // p2 p2->m = 7; // : p2.get()==0 Shape* ps = p3.get(); // auto_ptr<Shape> aps = p3; // // auto_ptr<Circle> p4 = pc; // : p4 }
auto_ptr
; , .
, , sort()
. :
// : auto_ptr void h(vector<auto_ptr<Shape> >& v) { sort(v.begin(),v.end()); // : },
auto_ptr
"" , -- , .
new
.. , :
5.3.4. New [expr.new]
typedef
.
: ? - :
The reason is the exception spacification is not part of the type; it is a constraint that is checked on assignment and exforced at run time (rather than at compile time). Some people would like it to be part of the type, but it isn't. The reason is to avoid difficulties when updating large systems with parts from different sources. See "The Design and Evolution of C++" for details., ; ( ). , , . , , , . " C++" .
, -- C++. , C++ ( exception safety) . , , Java, C++, .
, exception safe : ? .
, , nothrow
:
// nothrow : // f() void f() { // ... }
// f() , // void f() nothrow { // ... }
void f() { // nothrow { // nothrow- // , // , } // }
std::bad_exception
. - :
The standard doesn't support the mapping of exceptions as I describe it in 14.6.3. It specifies mapping tostd::bad_exception
for exceptions thrown explicitly within anunexpected()
function. This makesstd::bad_exception
an ordinary and rather pointless exception. The current wording does not agree with the intent of the proposer of the mechanism (Dmitry Lenkov of HP) and what he thought was voted in. I have raised the issue in the standards committee., 14.6.3.
std::bad_exception
,unexpected()
.std::bad_exception
, . () HP. issue .
, , :
15.5.2 unexpected()
[except.unexpected]
void unexpected();(stack unwinding).
unexpected()
, () . , , . , : std::bad_exception
(18.6.2.1), terminate()
, () std::bad_exception
.
std::bad_exception
, std::bad_exception
unexpected()
.
class XX : B { /* ... */ }; // B -- class YY : B { /* ... */ }; // B --
, :
class XX : B { /* ... */ }; // B -- struct YY : B { /* ... */ }; // B --.. ,
B
, : , , -- .
, -- , , .
, , , , , . .. : ... .
, , . .
, , C++ :
struct S { int i; void f(); }; void g() { cout<<&S::i; // : operator<< int S::* cout<<&S::f; // : operator<< void (S::*)() }. Andrew Koenig , /, , - (, , , ). , - , .. -- , .
:
#include <string.h> #include <stdio.h> struct S { int i1; int i2; void f1(); void f2(); virtual void vf1(); virtual void vf2(); }; const int SZ=sizeof(&S::f1); union { unsigned char c[SZ]; int i[SZ/sizeof(int)]; int S::* iptr; void (S::*fptr)(); } hack; void printVal(int s) { if (s%sizeof(int)) for (int i=0; i<s; i++) printf(" %02x", hack.c[i]); else for (int i=0; i<s/sizeof(int); i++) printf(" %0*x", sizeof(int)*2, hack.i[i]); printf("\n"); memset(&hack, 0, sizeof(hack)); } int main() { printf("sizeof(int)=%d sizeof(void*)=%d\n", sizeof(int), sizeof(void*)); hack.iptr=&S::i1; printf("sizeof(&S::i1 )=%2d value=", sizeof(&S::i1)); printVal(sizeof(&S::i1)); hack.iptr=&S::i2; printf("sizeof(&S::i2 )=%2d value=", sizeof(&S::i2)); printVal(sizeof(&S::i2)); hack.fptr=&S::f1; printf("sizeof(&S::f1 )=%2d value=", sizeof(&S::f1)); printVal(sizeof(&S::f1)); hack.fptr=&S::f2; printf("sizeof(&S::f2 )=%2d value=", sizeof(&S::f2)); printVal(sizeof(&S::f2)); hack.fptr=&S::vf1; printf("sizeof(&S::vf1)=%2d value=", sizeof(&S::vf1)); printVal(sizeof(&S::vf1)); hack.fptr=&S::vf2; printf("sizeof(&S::vf2)=%2d value=", sizeof(&S::vf2)); printVal(sizeof(&S::vf2)); } void S::f1() {} void S::f2() {} void S::vf1() {} void S::vf2() {}
hack
, ( ), printVal()
, .
, :
sizeof(int)=4 sizeof(void*)=4 sizeof(&S::i1 )= 8 value= 00000005 00000000 sizeof(&S::i2 )= 8 value= 00000009 00000000 sizeof(&S::f1 )=12 value= 004012e4 00000000 00000000 sizeof(&S::f2 )=12 value= 004012ec 00000000 00000000 sizeof(&S::vf1)=12 value= 004012d0 00000000 00000000 sizeof(&S::vf2)=12 value= 004012d8 00000000 00000000 sizeof(int)=4 sizeof(void*)=4 sizeof(&S::i1 )= 4 value= 00000001 sizeof(&S::i2 )= 4 value= 00000005 sizeof(&S::f1 )= 8 value= ffff0000 004014e4 sizeof(&S::f2 )= 8 value= ffff0000 004014f4 sizeof(&S::vf1)= 8 value= 00020000 00000008 sizeof(&S::vf2)= 8 value= 00030000 00000008 sizeof(int)=4 sizeof(void*)=4 sizeof(&S::i1 )= 4 value= 00000004 sizeof(&S::i2 )= 4 value= 00000008 sizeof(&S::f1 )= 4 value= 00401140 sizeof(&S::f2 )= 4 value= 00401140 sizeof(&S::vf1)= 4 value= 00401150 sizeof(&S::vf2)= 4 value= 00401160,
int
void*
, , . ?
- , .. "" (ffff0000 004014e4
), -- (00020000 00000008
). , , , int
, -1
(ffff
), , -- . - .
: ", , ? , ." , ! , : -.
, :
struct S { virtual void vf() { /* 1 */ } void f () { /* 2 */ } }; void g(void (S::*fptr)(), S* sptr) { (sptr->*fptr)(); } int main() { S s; g(S::vf, &s); g(S::f , &s); }:
void S_vf(S *const this) { /* 1 */ } void S_f (S *const this) { /* 2 */ } void S_vf_stub(S *const this) { // S::vf() (this->vptr[index_of_vf])(this); } void g(void (*fptr)(S *const), S* sptr) { fptr(sptr); } int main() { S s; g(S_vf_stub, &s); // : S_vf !!! g(S_f , &s); }C++ " -", , ..
size_t
, - ( ) . , , -, .
p
s
, Employee::operator new()
: p
, operator delete()
, .. .
: operator delete()
, ! .. :
void Employee::operator delete(void* p, size_t s) { if (!p) return; // // , p s , // Employee::operator new() // }, ,
p
template <class T> void std::allocator::deallocate(pointer p, size_type n);.
Pool::free
19.4.2. " , " .
. ..
A::~A() { // }( )
// A::~A(A *const this, bool flag) { if (this) { // if (flag) delete(this, sizeof(A)); } }
void f(Employee* ptr) { delete ptr; }
// void f(Employee* ptr) { Employee::~Employee(ptr, true); }..
Employee
, .
new[]
. , 10.3 "Array Allocation" "The Design and Evolution of C++" :
X
X::operator new()
X
( X
, ).
X* p = new X[10];
X::operator new()
, .. X[10]
, X
.
, .. X
. , .. X
-- X
, , , X
. , X::operator new()
, , . , ? , , X[d]
: , X[d][d2]
?
, , , , , . , , . , , .. . .
, / :
class X { // ... void* operator new(size_t sz); // void operator delete(void* p); void* operator new[](size_t sz); // void operator delete[](void* p); };. ,
operator new[]
; . , . Laura Yaker Mentor Graphics , .
, " " . :
#include <stdio.h> struct B1 { int b1; // virtual ~B1() { } }; struct B2 { int b2; // virtual B2* vfun() { printf("B2::vfun()\n"); // return this; } }; struct D : B1, B2 { // virtual D* vfun() { printf("D::vfun(): this=%p\n", this); return this; } }; int main() { D d; D* dptr=&d; printf("dptr\t%p\n", dptr); void* ptr1=dptr->vfun(); printf("ptr1\t%p\n", ptr1); B2* b2ptr=&d; printf("b2ptr\t%p\n", b2ptr); void* ptr2=b2ptr->vfun(); printf("ptr2\t%p\n", ptr2); }: " "
D::vfun()
, :
dptr 0012FF6C D::vfun(): this=0012FF6C ptr1 0012FF6C b2ptr 0012FF70 D::vfun(): this=0012FF6C ptr2 0012FF70..
D::vfun()
, (ptr1!=ptr2
), , , .
, 361 "12.2.6. ", this
this
. , , vtbl
. -, vtbl
:
// // D::vfun, D* D::vfun(D *const this) { // ... } // - D::vfun() // B2 B2* D::vfun_stub(B2 *const this) { return D::vfun(this+delta_1)+delta_2; }
delta_2
, , delta_1
.
, , " ". , , :
10.3. [class.virtual]
D::f
B::f
, , :
B::f
D::f
D::f
D
D::f
cv-, B::f
.
D::f
B::f
, D::f
D::f
D
. ( ), () (5.2.2). :
class B {}; class D : private B { friend class Derived; }; struct Base { virtual void vf1(); virtual void vf2(); virtual void vf3(); virtual B* vf4(); virtual B* vf5(); void f(); }; struct No_good : public Base { D* vf4(); // : B ( D) }; class A; struct Derived : public Base { void vf1(); // Base::vf1() void vf2(int); // , Base::vf2() char vf3(); // : D* vf4(); // OK: A* vf5(); // : void f(); }; void g() { Derived d; Base* bp=&d; // : Derived* Base* bp->vf1(); // Derived::vf1() bp->vf2(); // Base::vf2() bp->f(); // Base::f() ( ) B* p=bp->vf4(); // Derived::pf() // B* Derived* dp=&d; D* q=dp->vf4(); // Derived::pf(), // B* dp->vf2(); // : }
3.9.3. CV- [basic.type.qualifier]
cv- | < | const |
cv- | < | volatile |
cv- | < | const volatile |
const |
< | const volatile |
volatile |
< | const volatile |
, , STL . , , , ? , , , () . STL , ?
:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <list> struct List { // struct Data { int val; Data* next; Data(int v, Data* n=0) : val(v), next(n) {} }; Data *head, *tail; List() { head=tail=0; } ~List() { for (Data *ptr=head, *n; ptr; ptr=n) { // n=ptr->next; delete ptr; } } void push_back(int v) // { if (!head) head=tail=new Data(v); else tail=tail->next=new Data(v); } }; long Count, Var; void f1() { List lst; for (int i=0; i<1000; i++) lst.push_back(i); for (List::Data* ptr=lst.head; ptr; ptr=ptr->next) Var+=ptr->val; } void f2() { typedef std::list<int> list_type; list_type lst; for (int i=0; i<1000; i++) lst.push_back(i); for (list_type::const_iterator ci=lst.begin(), cend=lst.end(); ci!=cend; ++ci) Var+=*ci; } int main(int argc, char** argv) { if (argc>1) Count=atol(argv[1]); clock_t c1,c2; { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000; j++) f1(); c2=clock(); printf("f1(): %ld ths calls per %.1f sec\n", Count, double(c2-c1)/CLK_TCK); } { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000; j++) f2(); c2=clock(); printf("f2(): %ld ths calls per %.1f sec\n", Count, double(c2-c1)/CLK_TCK); } }
f1()
List
: 1000 , .
.. STL ( , ), :
struct List { // struct Data { // ... // static Data* free; static void allocate(); void* operator new(size_t); void operator delete(void*, size_t); }; // ... }; List::Data* List::Data::free; void List::Data::allocate() { const int sz=100; // sz free=reinterpret_cast<Data*>(new char[sz*sizeof(Data)]); // for (int i=0; i<sz-1; i++) free[i].next=free+i+1; free[sz-1].next=0; } inline void* List::Data::operator new(size_t) { if (!free) allocate(); Data* ptr=free; free=free->next; return ptr; } inline void List::Data::operator delete(void* dl, size_t) { // Data* ptr=static_cast<Data*>(dl); ptr->next=free; free=ptr; }, . memory leak ( ) -- memory pool, .. . , memory leak memory pool , : , , , , .
, -- (NULL
-). , , ..:
inline void List::Data::operator delete(void* dl, size_t) { if (!dl) return; // NULL // Data* ptr=static_cast<Data*>(dl); ptr->next=free; free=ptr; }, , --
std::list<int>
:
struct DList { // struct Data { int val; Data *prev, *next; Data(int v, Data* p=0, Data* n=0) : val(v), prev(p), next(n) {} // static Data* free; static void allocate(); void* operator new(size_t); void operator delete(void*, size_t); }; Data *head, *tail; DList() { head=tail=0; } ~DList() { for (Data *ptr=head, *n; ptr; ptr=n) { // n=ptr->next; delete ptr; } } void push_back(int v) // { if (!head) head=tail=new Data(v); else tail=tail->next=new Data(v, tail); } };, , . , :
|
|
|||||
f1() | f2() | f1() | f2() | f1() | f2() | |
1 | 9.6 | 12.1 | 1.1 | 12.1 | 1.3 | 12.1 |
2 | 20.2 | 2.5 | 1.8 | 2.5 | 1.9 | 2.5 |
?
vr
Record()
, s1
vi
int()
.
10 000 -- . 10 000 , , :
vector<X> vx; // vx.reserve(10000); // "" // push_back() // ... vx.push_back(x_work); //, .. STL 3.2 sgi
vector<int> vi(s1);:
for (int i=0; i<s1; i++) vi.elements[i]=0;
memset()
:
memset(vi.elements, 0, sizeof(int)*s1);( , ). Matt Austern , sgi STL .
, . "" O(log(N)), STL - , (10, ) , , O(N), . , reserve()
, , .
"", , char*
STL : -- , - . , :
void f(set<char*>& cset) { for (;;) { char word[100]; // word ... cset.insert(word); // : // } }
string
:
void f(set<string>& cset) { for (;;) { char word[100]; // word ... cset.insert(word); // OK: string } }
char*
STL , .. . sgi STL char*
:
struct ltstr { bool operator()(const char* s1, const char* s2) const { return strcmp(s1, s2) < 0; } }; int main() { const int N = 6; const char* a[N] = {"isomer", "ephemeral", "prosaic", "nugatory", "artichoke", "serif"}; set<const char*, ltstr> A(a, a + N); // .. }, C-, .
!
pair
.
, , , :
template <class T1,class T2> pair<T1,T2> std::make_pair(const T1& t1, const T2& t2) { return pair<T1,T2>(t1,t2); }: -, , .. . - :
char c=1; int i=2; // "" pair(c,i); // -- pair<char,int> pair<char,int>(c,i); // make_pair(c,i); //
operator[]()
.
, , .. , , , -- .
, : " " .
,
f<int>(); // f -- -
obj.f<int>(); // f -- -,, !
, - , :
template
, - ;
template
.
hash_map
.
"", ! , " hash_map
" . , STL, C++, hash_map
( ). - , hash_map
, , -- . , ...
(, , , )?
list<int>::const_iterator p=find_if(c.begin(),c.end(),bind2nd(less<int>(),7));:
list<int>::const_iterator p; for (p=c.begin(); p!=c.end(); ++p) if (*p<7) break;? -, . ? ,
bind2nd()
. *p>=5 && *p<100
, , , , find_if()
. : , .
, . , , - , .
- mem_fun()
. ,
for_each(lsp.begin(),lsp.end(),mem_fun(&Shape::draw)); //. ,
mem_fun()
, , (design pattern). -- . ?
, ? bind2nd()
, ? , ? -, .
, mem_fun()
- . , , , -- .
! .. remove()
, ( ) ?!
, , , -- !
, , ( ) C memcpy()
memmove()
. ? , . , : STL ( sgi) vector<int>
memmove()
.
__type_traits<>
-- . ( ) / POD , .
C++ POD (Plain Old Data). ? POD -- , ( memmove()
, ). ( ) .
? , , Date
POD :
class Date { int day, mon, year; // long val; // yyyymmdd public: // ... };
__type_traits<>
:
template<> struct __type_traits<Date> { // ... };:
__type_traits<>
-- , . , .
*
*(current-1)
...
, :
24.4.1.3.3 operator*
[lib.reverse.iter.op.star]
reference operator*() const;
Iterator tmp = current; return *--tmp;
I don't think anyone would use a reverse iterator if an iterator was an alternative, but then you never know what people might know. When you actually need to go through a sequence in reverse order a reverse iterator is often quite efficient compared to alternatives. Finally, there may not be any overhead because where the iterator is a vector the temporary isn't hard to optimize into a register use. One should measure before worrying too much about overhead., - , , , . , . , , , - . , .
, - , ().
, .
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <list> long Count, Var; typedef std::list<int> list_type; list_type lst; void f1() { for (list_type::reverse_iterator ri=lst.rbegin(), rend=lst.rend(); ri!=rend; ++ri) Var+=*ri; } void f2() { list_type::iterator i=lst.end(), beg=lst.begin(); if (i!=beg) { do { --i; Var+=*i; } while (i!=beg); } } int main(int argc, char** argv) { if (argc>1) Count=atol(argv[1]); for (int i=0; i<10000; i++) lst.push_back(i); clock_t c1, c2; { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000; j++) f1(); c2=clock(); printf("f1(): %ld ths calls per %.1f sec\n", Count, double(c2-c1)/CLK_TCK); } { c1=clock(); for (long i=0; i<Count; i++) for (long j=0; j<1000; j++) f2(); c2=clock(); printf("f2(): %ld ths calls per %.1f sec\n", Count, double(c2-c1)/CLK_TCK); } }10 000 ( ) (
f1()
) ( f2()
) . , "" 45% 2.4 .
: ? :
void f1() { for (list_type::iterator i=lst.begin(), end=lst.end(); i!=end; ++i) Var+=*i; } void f2() { for (list_type::iterator i=lst.begin(), end=lst.end(); i!=end; i++) Var+=*i; }: , , , 5 - 30 .
, , .
: ? C++ ""? -. :
Something that would allow a copy constructor to be defined using a user-defined reference object.-, .
template<class T> T* Pool_alloc<T>::allocate(size_type n, void* =0) { if (n==1) return static_cast<T*>(mem_alloc()); // ... }
, . allocate<>()
n!=1
? mem_alloc()
? , . ? Pool_alloc<char>
. Pool
:
Pool::Pool(unsigned int sz) : esize(sz<sizeof(Link*) ? sizeof(Link*) : sz) { // ... },
sz==sizeof(char)
char
sizeof(Link*)
. "" ! .. X
, sizeof(X)<sizeof(Link*)
, deallocate<>()
, , .
template<class T, class A> T* temporary_dup(vector<T,A>& v) { T* p=get_temporary_buffer<T>(v.size()).first; if (p==0) return 0; copy(v.begin(),v.end(),raw_storage_iterator<T*,T>(p)); return p; }
, , .. get_temporary_buffer<>()
. .. get_temporary_buffer<>()
, , :
template<class T, class A> T* temporary_dup(vector<T,A>& v) { pair<T*,ptrdiff_t> p(get_temporary_buffer<T>(v.size())); if (p.second<v.size()) { if (p.first) return_temporary_buffer(p.first); return 0; } copy(v.begin(),v.end(),raw_storage_iterator<T*,T>(p)); return p.first; }
assign(s,n,x)
assign(s[i],x)
n
x
s
.compare()
lt()
eq()
.
, char_traits<char>
, , lt()
, eq()
, assign(s[i],x)
, memcmp()
memset()
, , , . .. strcmp()
, , , string
30% , C char*
strcmp()
. : string
char
.
basic_string
, ().
, , basic_string::c_str()
. , () [const
] char*
[const
] string&
, , "" , .
, , char*
C . , , , , , '-
' '+
', .
, , string
, , , memcpy()
, "" .
(.. ). , sgi STL 3.2 , . , .
, - . , , .. ( Herb Sutter Reference Counting - Part III), -- .
, : , , , .
, , , , const string&
.
(cerr.operator<<("x=")).operator<<(x);
: - -, :
operator<<(cerr,"x=").operator<<(x);! : , - , -- !
, , , .
: C++ . C, -- (, , FILE*
C, C++ ; , !). :
#include <stdio.h> #include <time.h> #include <io.h> // open() #include <fcntl.h> #include <iostream> #include <fstream> using namespace std; void workc(char*); void workcpp(char*); void work3(char*); int main(int argc, char **argv) { if (argc==3) switch (*argv[2]-'0') { case 1: { workc(argv[1]); break; } case 2: { workcpp(argv[1]); break; } case 3: { work3(argv[1]); break; } } } void workc(char* fn) { FILE* fil=fopen(fn, "rb"); if (!fil) return; time_t t1; time(&t1); long count=0; while (getc(fil)!=EOF) count++; time_t t2; time(&t2); fclose(fil); cout<<count<<" bytes per "<<t2-t1<<" sec.\n" ; } void workcpp(char* fn) { ifstream fil(fn, ios_base::in|ios_base::binary); if (!fil) return; time_t t1; time(&t1); long count=0; while (fil.get()!=EOF) count++; time_t t2; time(&t2); cout<<count<<" bytes per "<<t2-t1<<" sec.\n" ; } class File { int fd; // unsigned char buf[BUFSIZ]; // unsigned char* gptr; // unsigned char* bend; // int uflow(); public: File(char* fn) : gptr(0), bend(0) { fd=open(fn, O_RDONLY|O_BINARY); } ~File() { if (Ok()) close(fd); } int Ok() { return fd!=-1; } int gchar() { return (gptr<bend) ? *gptr++ : uflow(); } }; int File::uflow() { if (!Ok()) return EOF; int rd=read(fd, buf, BUFSIZ); if (rd<=0) { // EOF close(fd); fd=-1; return EOF; } gptr=buf; bend=buf+rd; return *gptr++; } void work3(char* fn) { File fil(fn); if (!fil.Ok()) return; time_t t1; time(&t1); long count=0; while (fil.gchar()!=EOF) count++; time_t t2; time(&t2); cout<<count<<" bytes per "<<t2-t1<<" sec.\n" ; }. -- () , -- 1, 2 3,
workc()
, workcpp()
work3()
. , .. .
work3()
File
. "" - C -- FILE*
. , workc()
work3()
, , , .
: .
? ! ( ) 11 !!!
, .
C getc()
:
#define getc(f) ((--((f)->level) >= 0) ? (unsigned char)(*(f)->curp++) : _fgetc (f)).. . -- -. C++ , : - , - ?!
: -- ! , ?
void workc(char* fn) { // ... if (setvbuf(fil, 0, _IOFBF, LARGE_BUFSIZ)) return; // ... } void workcpp(char* fn) { // ... char* buf=new char[LARGE_BUFSIZ]; fil.rdbuf()->pubsetbuf(buf, LARGE_BUFSIZ); // ... delete [] buf; }, ! , , ( , ).
, , . , . , .. .
, , - , C++ .
printf()
. ? dd.mm.yyyy
:
int day= 31, mon= 1, year=1974; printf("%02d.%02d.%d\n", day, mon, year); // 31.01.1974 cout<<setfill('0')<<setw(2)<<day<<'.'<<setw(2)<<mon<<setfill(' ')<<'.' <<year<<"\n"; // 31.01.1974, .
C C++ ? C++ -- . .. C++ , , , , ...printf()
. :
cout<<c_form(day,"02")<<'.'<<c_form(mon,"02")<<'.'<<year<<'\n';:
#include <ostream> /** c_form, */ namespace c_form_private { typedef std::ios_base::fmtflags fmtflags; typedef std::ostream ostream; typedef std::ios_base ios; /** * . */ class Formatter { /** */ fmtflags newFlags; /** */ int width; /** */ int prec; /** - */ char fill; /** */ fmtflags oldFlags; public: /** * , . */ Formatter(const char* form, int arg1, int arg2); /** * , * . */ void setFormatting(ostream& os); /** * , * setFormatting(). */ void restoreFormatting(ostream& os); }; /** * . */ template <class T> class Helper { /** */ const T& val; /** */ mutable Formatter fmtr; public: /** * . */ Helper(const T& val_, const char* form, int arg1, int arg2) : val(val_), fmtr(form, arg1, arg2) {} /** * . */ void putTo(ostream& os) const; }; template <class T> void Helper<T>::putTo(ostream& os) const { fmtr.setFormatting(os); os<<val; fmtr.restoreFormatting(os); } /** * Helper . */ template <class T> inline ostream& operator<<(ostream& os, const Helper<T>& h) { h.putTo(os); return os; } } /** * -, , * ostream. * . * @param val * @param form : [-|0] [|*] [.(|*)] [e|f|g|o|x] * @param arg1 , . * @param arg2 , . * @throws std::invalid_argument form * . */ template <class T> inline c_form_private::Helper<T> c_form(const T& val, const char* form, int arg1=0, int arg2=0) { return c_form_private::Helper<T>(val, form, arg1, arg2); }-:
#include "c_form.hpp" #include <stdexcept> #include <cctype> namespace { /** * . */ int getval(const char*& iptr) { int ret=0; do ret=ret*10 + *iptr-'0'; while (std::isdigit(*++iptr)); return ret; } } c_form_private::Formatter::Formatter(const char* form, int arg1, int arg2) : newFlags(fmtflags()), width(0), prec(0), fill(0) { const char* iptr=form; // if (*iptr=='-') { // newFlags|=ios::left; iptr++; } else if (*iptr=='0') { // '0' !left fill='0'; iptr++; } if (*iptr=='*') { // , width=arg1; iptr++; arg1=arg2; // } else if (std::isdigit(*iptr)) width=getval(iptr); if (*iptr=='.') { // if (*++iptr=='*') { prec=arg1; iptr++; } else if (std::isdigit(*iptr)) prec=getval(iptr); else throw std::invalid_argument("c_form"); } switch (*iptr++) { case 0: return; // case 'e': newFlags|=ios::scientific; break; case 'f': newFlags|=ios::fixed; break; case 'g': break; case 'o': newFlags|=ios::oct; break; case 'x': newFlags|=ios::hex; break; default: throw std::invalid_argument("c_form"); } if (*iptr) throw std::invalid_argument("c_form"); } void c_form_private::Formatter::setFormatting(ostream& os) { oldFlags=os.flags(); // floatfield os.flags((oldFlags & ~ios::floatfield) | newFlags); if (width) os.width(width); if (fill) fill=os.fill(fill); if (prec) prec=os.precision(prec); } void c_form_private::Formatter::restoreFormatting(ostream& os) { os.flags(oldFlags); if (fill) os.fill(fill); if (prec) os.precision(prec); }:
c_form<>()
c_form_private::Helper<>
, ostream
.
, c_form<>()
, .. - c_form<>
, :
cout<<c_form<int>(day,"02");, , . . , ,
Formatter
, Helper<>
, ( ) .
, c_form
. , , () .
readsome()
, ...
.. readsome()
, :
27.6.1.3 [lib.istream.unformatted]
streamsize readsome(char_type* s, streamsize n);
!good()
setstate(failbit)
, . , s
. rdbuf()->in_avail() == -1
, setstate(eofbit)
( ios_base::failure
(27.4.4.3)) ;
rdbuf()->in_avail() == 0
,
rdbuf()->in_avail() > 0
, min(rdbuf()->in_avail(),n))
, , .. . , Circle
Ellipse
, is-a: . , .
, , : a
b
. . , , .. . -- , , . , , .. , .
? , , .. . , (, , b
-- ). , , (), .. , , .
.. C++ , . :
T(*e)(int(3)); |
T* e(int(3)); |
, int , : . |
|
T(f)[4]; |
T f[4]; |
||
T(a); |
T a; |
||
T(a)=m; |
T a=m; |
||
T(*b)(); |
. | ||
T(x),y,z=7; |
T x,y,z=7; |
template<class C> class Basic_ops { // friend bool operator==<>(const C&, const C&); // friend bool operator!=<>(const C&, const C&); // ... };(
<>
) , - ( ).
10 .
<>
? operator==()
, .. operator==()
-. :
14.5.3. [temp.friend]
template<class T> class task; template<class T> task<T>* preempt(task<T>*); template<class T> class task { // ... friend void next_time(); friend void process(task<T>*); friend task<T>* preempt<T>(task<T>*); template<class C> friend int func(C); friend class task<int>; template<class P> friend class frd; // ... };
next_time
- task
; .. process
template-arguments, - task
- process
-; .. preempt
template-argument <T>
, - task
- preempt
; , , - task
- func
. , - task
- task<int>
, - frd
.
template
- - . , - -? :
template <class T> void get_new3(); // (1) template <class Allocator> void f(Allocator& m) { int* p1= m.template get_new1<int>( ); int* p2=Allocator::template get_new2<int>(m); int* p3= get_new3<int>(m); } struct Alloc { template <class T> T* get_new1() { return 0; } template <class T> static T* get_new2(Alloc&) { return 0; } template <class T> friend T* get_new3(Alloc&) { return 0; } }; int main() { Alloc a; f(a); }:
get_new1
--- -, template
. , f
Allocator
, -- () (m.get_new1) < int...
get_new2
-- -, f
, template
.
get_new3
-- Alloc
, . , f
Alloc
( , get_new1
get_new2
). f
, , get_new3
f
-. f
, (1) get_new3
-- Alloc
, ( !) - get_new3
. , f
--
p3=get_new3<int>(m);, -. , (1)
get_new3
. , ( ) get_new3
, f
.
p3=template get_new3<int>(m);, ,
template
C++.
? ? ? , . , :
, , -- ! ? , ; . ? .
, "" , .. . -- "". , . , , . , -- . , -- . , , ( : (!) - UPDATE STATISTICS
; , SQL- . " " ).
, . , . - . "" SQL- , , , . "" .
, .. ( , ). ""- ( , . , ) " " (, , int
, ). -- .
, . ? . , , , :
, ( : a+a
2*a
, register int i;
..), ( , " " ). .
( O(N*N), O(N*log(N)) O(N*M) ). ! , , , . , "" !
, . . , , -. , . , , sin(x)
, ( 360 int
). "" -- switch
. , ( O(1)) ( O(log(N))) -- O(N), switch
. switch
.
. C++.
, , - C++ , . , " ", .. () C++, .
C++ C . .. , , , . ( _fastcall
), , . :
void f1(int arg) { Var+=arg; } void _fastcall f2(int arg) { Var+=arg; }
f1()
50% . , . .
-- . ? , -- , , 90% ! , , , . .
( ), , . , . - ? f()
file1.cpp
g()
file2.cpp
, , , file2.cpp
. , , file2.cpp
- g2()
, g()
- ; -... , , .
Paul Hsieh "Programming Optimization". , "", , , Steve Heller "Optimizing C++".
, , . , C++, .
, ?
_VAL_
, :
#define _VAL_(var) #var "=" << var << " ", ( ) , . .
_ADD_
. :
cout<<_ADD_(" ");-
<file.cpp:34>,
cout<<" " _ADD_("") "\n";,
_ADD_
.
char* _ADD_(char*);, . ,
cout
, .
_ADD_
:
#define _ADD_tmp_tmp_(str,arg) str " <" __FILE__ ":" #arg ">" #define _ADD_tmp_(str,arg) _ADD_tmp_tmp_(str,arg) #define _ADD_(str) _ADD_tmp_(str,__LINE__)? ,
__LINE__
__FILE__
, . , , :
#define _ADD_(str) str " <" __FILE__ ":" #__LINE__ ">"..
#
. __LINE__
,
#define _ADD_tmp_(str,arg) str " <" __FILE__ ":" #arg ">" #define _ADD_(str) _ADD_tmp_(str,__LINE__):
_ADD_(" ")
" <file.cpp:__LINE__>". , :
_ADD_(" ")
_ADD_tmp_(" ",__LINE__) _ADD_tmp_tmp_(" ",34) " " " <" "file.cpp" ":" "34" ">" " <file.cpp:34>"
DB::Query
void DB::Query::Statement(const char *);, " "
somefield
:
#define FieldOK 7 // ... DB::Int tmp(FieldOK); q.Statement(" SELECT * " " FROM sometable " " WHERE somefield=? " ); q.SetParam(), tmp;.
FieldOK
? :
#define FieldOK 7 // ... #define FieldOK_CHAR "7" // ... q.Statement(" SELECT * " " FROM sometable " " WHERE somefield=" FieldOK_CHAR );.
#define FieldOK 7 // ... q.Statement(" SELECT * " " FROM sometable " " WHERE somefield=" _GETSTR_(FieldOK) );
_GETSTR_
:
#define _GETSTR_(arg) #arg, C++
const int FieldOK=7; enum { FieldOK=7 };
_GETSTR_
.
struct Table1 { // DB::Date Field1; DB::Int Field2; DB::Short Field3; }; void f() { Table1 tbl; DB::Query q; q.Statement(" SELECT Field1, Field2, Field3 " " FROM Table1 " ); q.BindCol(), tbl.Field1, tbl.Field2, tbl.Field3; // ... }. , ? -- ! :
#define TABLE1_FLD Field1, Field2, Field3 #define TABLE1_FLD_CHAR "Field1, Field2, Field3" struct Table1 { // DB::Date Field1; DB::Int Field2; DB::Short Field3; // void BindCol(DB::Query& q) { q.BindCol(), TABLE1_FLD; } }; void f() { Table1 tbl; DB::Query q; q.Statement(" SELECT " TABLE1_FLD_CHAR " FROM Table1 " ); tbl.BindCol(q); // ... }. ,
TABLE1_FLD_CHAR
_GETSTR_(TABLE1_FLD)
, .. TABLE1_FLD
. , C++ .
q.Statement(" SELECT Field1, AccA_bal, AccA_cur, AccA_key, AccA_brn, " " AccA_per, Field2 " " FROM Table1 " ); q.BindCol(), tbl.Field1, tbl.AccA.bal, tbl.AccA.cur, tbl.AccA.key, tbl.AccA.brn, tbl.AccA.per, tbl.Field2; // ..., (
tbl.AccA
, tbl.AccB
, tbl.KorA
, tbl.KorB
). :
#define _SACC_(arg) #arg"_bal, "#arg"_cur, "#arg"_key, "#arg"_brn, " \ #arg"_per " #define _BACC_(arg) arg.bal, arg.cur, arg.key, arg.brn, arg.per // ... q.Statement(" SELECT Field1, " _SACC_(AccA) " , Field2 " " FROM Table1 " ); q.BindCol(), tbl.Field1, _BACC_(tbl.AccA), tbl.Field2; // ..., .
struct A { MyDate Date; int Field2; short Field3; };
Date
, .. DATE
SQL. :
struct TableA { DB::Date xDate; DB::Int xField2; DB::Short xField3; TableA& operator=(A&); void Clear(); };-:
TableA& TableA::operator=(A& a) { xDate=ToDB(a.Date); xField2=ToDB(a.Field2); xField3=ToDB(a.Field3); return *this; } void TableA::Clear() { xDate=""; xField2=""; xField3=""; },
TableA
- , , ! , ? :
TableA& TableA::operator=(A& a) { // : ## #define ASS(arg) x##arg=ToDB(a.arg); ASS(Date); ASS(Field2); ASS(Field3); #undef ASS return *this; } void TableA::Clear() { #define CLR(arg) x##arg="" CLR(Date); CLR(Field2); CLR(Field3); #undef CLR }
TableA::Clear()
TableA::operator=()
, , , . : A& A::operator=(TableA&)
.
.
Last-modified: Thu, 07 Dec 2006 05:46:12 GMT