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