; } 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); B