2* 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" ; }