Upload
jon-jagger
View
2.229
Download
0
Tags:
Embed Size (px)
DESCRIPTION
A talk I first gave at Amadeus in Nice, 18th April 2013. Includes the #include test.
Citation preview
some stuff about C++ and development
sequence points
5.1.2.3 Program execution. Clause 2
At certain specified points in the execution sequence called
sequence points, all side effects of previous evaluations shall be
complete and no side effects of subsequent evaluation shall have
taken place.
sequence points
program state
side effects
time
sequence points
program state
side effects
time
sequence points
program state
side effects
time
sequence points
program state
side effects
time
sequence points
program state
side effects
time
sequence points
program state
side effects
time
sequence points
program state
side effects
time
sequence points
program state
side effects
time
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
Most C and C++ programmers use an implicit mental model made up of lots of sequence points,
progressing in a mostly left-to-right order.
i + v[++i] + v[++i]
sequence points
In reality C and C++ have very few sequence points(this is to give maximum scope for optimization).
sequence points where?
• at the end of a full expression
• after the first operand of these operators && || ?: ,
• after evaluation of all arguments and the function call expression in a function call
only sequence points
govern the order of evaluation
got it?
sequence points
i = v[++i] + v[++i];
question: where are the sequence points in this statement ?
sequence points
i = v[++i] + v[++i];
answer: here!
why does this matter?
I'm glad you asked!
here's why...
shall
If a "shall" or a "shall not" requirement that appears outside of a constraint is
violated, the behavior is undefined.
4. Conformance. Clause 2
undefined behavior: behavior ... for which this International Standard imposes no requirements.
3. Terms, definitions, and symbols
sequence point: rule-one
Between the previous and next sequence point an object shall have its stored value modified at most once by
the evaluation of an expression.
n = n++;
6.5 Expressions. Clause 2.
undefined behavior
sequence point: rule-one
Between the previous and next sequence point an object shall have its stored value modified at most once by
the evaluation of an expression.
n = n++;
6.5 Expressions. Clause 2.
undefined behavior
sequence point: rule-two
Between the previous and next sequence point the prior value shall be read only to determine the value to be
stored.
n + n++;
6.5 Expressions. Clause 2.
undefined behavior
sequence point: rule-two
Between the previous and next sequence point the prior value shall be read only to determine the value to be
stored.
n + n++;
6.5 Expressions. Clause 2.
undefined behavior
example#include <stdio.h>
int main(void){ int v[] = { 0,2,4,6,8 }; int i = 1; int n = i + v[++i] + v[++i]; printf("%d\n", n);}
$ gcc foo.c && ./a.out
gcc
(Mac OS 10.8.2)
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>
int main(void){ int v[] = { 0,2,4,6,8 }; int i = 1; int n = i + v[++i] + v[++i]; printf("%d\n", n);}
$ gcc foo.c && ./a.out
gcc
(Mac OS 10.8.2)
$ gcc foo.c && ./a.out12
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>
int main(void){ int v[] = { 0,2,4,6,8 }; int i = 1; int n = i + v[++i] + v[++i]; printf("%d\n", n);}
$ gcc foo.c && ./a.out
gcc
$ clang foo.c && ./a.out
clang
(Mac OS 10.8.2)
$ gcc foo.c && ./a.out12
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>
int main(void){ int v[] = { 0,2,4,6,8 }; int i = 1; int n = i + v[++i] + v[++i]; printf("%d\n", n);}
$ gcc foo.c && ./a.out
gcc
$ clang foo.c && ./a.out
clang
(Mac OS 10.8.2)
$ gcc foo.c && ./a.out12
$ clang foo.c && ./a.out11
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>
int main(void){ int v[] = { 0,2,4,6,8 }; int i = 1; int n = i + v[++i] + v[++i]; printf("%d\n", n);}
$ gcc foo.c && ./a.out
gcc
$ clang foo.c && ./a.out
clang
$ icc foo.c && ./a.out
icc
(Mac OS 10.8.2)
$ gcc foo.c && ./a.out12
$ clang foo.c && ./a.out11
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>
int main(void){ int v[] = { 0,2,4,6,8 }; int i = 1; int n = i + v[++i] + v[++i]; printf("%d\n", n);}
$ gcc foo.c && ./a.out
gcc
$ clang foo.c && ./a.out
clang
$ icc foo.c && ./a.out
icc
(Mac OS 10.8.2)
$ gcc foo.c && ./a.out12
$ clang foo.c && ./a.out11
$ icc foo.c && ./a.out13
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
a reference toa[i]
can also be written as *(a+i)
5.3 Pointers and Arrays
example
#include <stdio.h>
int main(void) { int src[] = { 1,2,3,4 }; int dst[] = { 0,0,0,0 }; int i = 1; dst[i] = src[i++]; printf("%d %d %d %d\n", dst[0], dst[1], dst[2], dst[3]);}
$ gcc *.c && ./a.out
gcc 4.8.0 20130210
example
#include <stdio.h>
int main(void) { int src[] = { 1,2,3,4 }; int dst[] = { 0,0,0,0 }; int i = 1; dst[i] = src[i++]; printf("%d %d %d %d\n", dst[0], dst[1], dst[2], dst[3]);}
$ gcc *.c && ./a.out$ gcc *.c && ./a.out0 2 0 0
gcc 4.8.0 20130210
example
#include <stdio.h>
int main(void) { int src[] = { 1,2,3,4 }; int dst[] = { 0,0,0,0 }; int i = 1; dst[i] = src[i++]; printf("%d %d %d %d\n", dst[0], dst[1], dst[2], dst[3]);}
$ gcc *.c && ./a.out$ gcc *.c && ./a.out0 2 0 0
gcc 4.8.0 20130210
#include <stdio.h>
int main(void) { int src[] = { 1,2,3,4 }; int dst[] = { 0,0,0,0 }; int i = 1; *(dst + i) = *(src + i++); printf("%d %d %d %d\n", dst[0], dst[1], dst[2], dst[3]);}
example
#include <stdio.h>
int main(void) { int src[] = { 1,2,3,4 }; int dst[] = { 0,0,0,0 }; int i = 1; dst[i] = src[i++]; printf("%d %d %d %d\n", dst[0], dst[1], dst[2], dst[3]);}
$ gcc *.c && ./a.out $ gcc *.c && ./a.out$ gcc *.c && ./a.out0 2 0 0
gcc 4.8.0 20130210
#include <stdio.h>
int main(void) { int src[] = { 1,2,3,4 }; int dst[] = { 0,0,0,0 }; int i = 1; *(dst + i) = *(src + i++); printf("%d %d %d %d\n", dst[0], dst[1], dst[2], dst[3]);}
example
#include <stdio.h>
int main(void) { int src[] = { 1,2,3,4 }; int dst[] = { 0,0,0,0 }; int i = 1; dst[i] = src[i++]; printf("%d %d %d %d\n", dst[0], dst[1], dst[2], dst[3]);}
$ gcc *.c && ./a.out $ gcc *.c && ./a.out$ gcc *.c && ./a.out0 2 0 0
$ gcc *.c && ./a.out0 0 2 0
gcc 4.8.0 20130210
#include <stdio.h>
int main(void) { int src[] = { 1,2,3,4 }; int dst[] = { 0,0,0,0 }; int i = 1; *(dst + i) = *(src + i++); printf("%d %d %d %d\n", dst[0], dst[1], dst[2], dst[3]);}
precedence is not the same as order of
evaluation
order of evaluation is mostly unspecified
and is a run-time thing
precedence iscompletely specified
and is a compile-time thing
precedence determines which operands
bind to which operators
a * b + c
example
a * b + c?
a * b + c?
a() * b() + c()
temp_a = a();temp_b = b();temp_c = c();a * b + c
temp_c = c();temp_b = b();temp_a = a();a * b + c
temp_b = b();temp_c = c();temp_a = a();a * b + c
example#include <iostream>...int main(){ int sum = a() + b(); std::cout << sum;}
#include <iostream>...int a(){ std::cout << "a"; return 3;}
#include <iostream>...int b(){ std::cout << "b"; return 4;}
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <iostream>...int main(){ int sum = a() + b(); std::cout << sum;}
$ g++ *.c && ./a.out
#include <iostream>...int a(){ std::cout << "a"; return 3;}
#include <iostream>...int b(){ std::cout << "b"; return 4;}
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <iostream>...int main(){ int sum = a() + b(); std::cout << sum;}
$ g++ *.c && ./a.out
#include <iostream>...int a(){ std::cout << "a"; return 3;}
#include <iostream>...int b(){ std::cout << "b"; return 4;}
$ g++ *.c && ./a.outab7
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <iostream>...int main(){ int sum = a() + b(); std::cout << sum;}
$ g++ *.c && ./a.out $ g++ *.c && ./a.out
#include <iostream>...int a(){ std::cout << "a"; return 3;}
#include <iostream>...int b(){ std::cout << "b"; return 4;}
$ g++ *.c && ./a.outab7
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <iostream>...int main(){ int sum = a() + b(); std::cout << sum;}
$ g++ *.c && ./a.out $ g++ *.c && ./a.out
#include <iostream>...int a(){ std::cout << "a"; return 3;}
#include <iostream>...int b(){ std::cout << "b"; return 4;}
$ g++ *.c && ./a.outab7
$ g++ *.c && ./a.outba7
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
indeterminate value
6.2.4 Storage duration of objects
The initial value of the object is indeterminate.
J.2 Undefined behavior
The value of an object with automatic storage duration is used while it is indeterminate.
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc
Without optimization...
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc
Without optimization...
true
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang
Without optimization...
true
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang
Without optimization...
true false
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang icc
Without optimization...
true false
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang icc
Without optimization...
true false truefalse
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang icc
Without optimization...
With optimization...
true false truefalse
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang icc
Without optimization...
With optimization...
true false truefalse
false
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang icc
Without optimization...
With optimization...
true false truefalse
false
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang icc
Without optimization...
With optimization...
true false truefalse
false false
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang icc
Without optimization...
With optimization...
true false truefalse
false false
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
example#include <stdio.h>#include <stdbool.h>
void bar(void){ bool b; if (b) printf("true\n"); if (!b) printf("false\n");}
void foo(void);void bar(void);
int main(void){ foo(); bar();}
void foo(void){ char c = 2; ...}
gcc clang icc
Without optimization...
With optimization...
true false truefalse
false false false
http://www.pvv.org/~oma/UnspecifiedAndUndefined_ACCU_Apr2013.pdf
why do cars have brakes?
so you can drive faster!
do you do unit testing?
what do you mean by the word
unit ?
it's nothing to do with size
A
tests
A
tests
B
A
tests
C
B
A
tests
C
B
D
A
tests
C
B
D
E
A
tests
C
B
F
D
E
A
tests
C
B
FG
D
E
A
tests
C
B
FG
D
E
extern
al boundary
A
tests
C
B
FG
D
database
extern
al boundary
A
tests
C
B
Fregistry
D
database
extern
al boundary
A
tests
C
B
Fregistry
D
file system
extern
al boundary
A
tests
C
B
Fsocket
D
file system
extern
al boundary
A
tests
C
B
F
socket
D
file system
extern
al boundary
unit tests should pass or fail based solely on the correctness of our tests
and our code
A
tests
C
B
F
socket
D
file system
extern
al boundary
not based on the correctness of external code and its environment
this means we have to design "seams"
into our architecture
A
tests
C
B
F
socket
D
file system
substitutefile system
substitutesocket
seam
seam
this is a useful
definition
it means unit tests
are...
so fast, your basic development
activity can change from...
re-compiling
to...
re-running the unit tests
this is not a mere quantitative
change
it is a qualitative change
some more about tests being...
void example_of_use(){ q = snafu::instance().query(...) ... snafu::instance().modifier(...); ...}
spot the anti-pattern
class snafu {public: // singleton static snafu & instance(); public: // api int query(...) const; void modifier(...);
private: // inappropriate snafu(const snafu &); snafu & operator=(const snafu &); private: // 'tors snafu(); ~snafu(); };
singleton
this is the only good singleton
A
tests
C
B
F
socket
D
file system
substitutefile system
substitutesocket
seam
seam
1
singleton
A
unittest
C
B
F
D
1
danger
A
unittest
C
B
F
D
1
anotherunittest
danger
you should be able to run your
unit tests in any order
you should be able to run your
unit tests in parallel
unit tests
integration
system
no externaldependencies
some externaldependencies
all externaldependencies
waterfall
anal
ysis
desi
gn
impl
emen
t
test
waterfall
anal
ysis
desi
gn
impl
emen
t
debu
g
Debugging is twice as hard as writing the code in the first
place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart
enough to debug it.
"agile"... ... ...test ... ... ...test ... ... ...test
virtual destructor?
class dice_roller{public: virtual ~dice_roller(); ... virtual int roll_dice() const = 0;};
question:what does a virtual destructor mean?
virtual destructor
class random_dice_roller : public dice_roller{public: ...};
answer:any code can delete a derived object through a base class pointers*
void contrived_example(){ dice_roller * ptr = new random_dice_roller(); ... delete ptr;}
* and it will work!
virtual destructor
class random_dice_roller : public dice_roller{public: ...};
answer:any code can delete a derived object through a base class pointers*
void contrived_example(){ dice_roller * ptr = new random_dice_roller(); ... delete ptr;}
* and it will work!
virtual destructor?
class random_dice_roller : public dice_roller{public: ...};
question:should any code be able to write delete expressions?
void contrived_example(){ dice_roller * ptr = new random_dice_roller(); ... delete ptr;}
class dice_roller{public: virtual ~dice_roller(); ...};
virtual destructor
suppose you don't want arbitrary code to be able to write delete expressions?
void contrived_example(){ dice_roller * ptr = new random_dice_roller(); ... delete ptr;}
class dice_roller{public: ...protected: ~dice_roller();};
bad inheritance
alpha
beta
gamma
delta
new alpha()
new beta()
new gamma()
new delta()
good inheritance
alpha beta gamma
abstraction
delta
client
factory pattern
abstractfactory
abstractproduct
concreteproduct
concretefactory
<<creates>>
<<creates>>
client
#include header
#include "wibble.hpp"
class fubar {
};
inheritance
#include "wibble.hpp"
class fubar : public wibble // 1{
};
member function parameters
#include "wibble.hpp"
class fubar : public wibble // 1{ void value_parameter(wibble ); // 2 void ref_parameter(wibble &); // 3 void ptr_parameter(wibble *); // 4
};
member function return types
#include "wibble.hpp"
class fubar : public wibble // 1{ void value_parameter(wibble ); // 2 void ref_parameter(wibble &); // 3 void ptr_parameter(wibble *); // 4
wibble value_result(); // 5 wibble & ref_result(); // 6 wibble * ptr_result(); // 7
};
data members
#include "wibble.hpp"
class fubar : public wibble // 1{ void value_parameter(wibble ); // 2 void ref_parameter(wibble &); // 3 void ptr_parameter(wibble *); // 4
wibble value_result(); // 5 wibble & ref_result(); // 6 wibble * ptr_result(); // 7
wibble value; // 8 wibble & ref; // 9 wibble * ptr; // 10
};
static data member#include "wibble.hpp"
class fubar : public wibble // 1{ void value_parameter(wibble ); // 2 void ref_parameter(wibble &); // 3 void ptr_parameter(wibble *); // 4
wibble value_result(); // 5 wibble & ref_result(); // 6 wibble * ptr_result(); // 7
wibble value; // 8 wibble & ref; // 9 wibble * ptr; // 10
static wibble shared_value; // 11 static wibble & shared_ref; // 12 static wibble * shared_ptr; // 13};
forward declarationclass wibble;
class fubar : public wibble // 1{ void value_parameter(wibble ); // 2 void ref_parameter(wibble &); // 3 void ptr_parameter(wibble *); // 4
wibble value_result(); // 5 wibble & ref_result(); // 6 wibble * ptr_result(); // 7
wibble value; // 8 wibble & ref; // 9 wibble * ptr; // 10
static wibble shared_value; // 11 static wibble & shared_ref; // 12 static wibble * shared_ptr; // 13};
which of 1..13 require #include ?#include "wibble.hpp"
class fubar : public wibble // 1{ void value_parameter(wibble ); // 2 void ref_parameter(wibble &); // 3 void ptr_parameter(wibble *); // 4
wibble value_result(); // 5 wibble & ref_result(); // 6 wibble * ptr_result(); // 7
wibble value; // 8 wibble & ref; // 9 wibble * ptr; // 10
static wibble shared_value; // 11 static wibble & shared_ref; // 12 static wibble * shared_ptr; // 13};
my assistant will now collect up the
answers
the answer is...
class wibble;
class fubar : public wibble // 1{ void value_parameter(wibble ); // 2 void ref_parameter(wibble &); // 3 void ptr_parameter(wibble *); // 4
wibble value_result(); // 5 wibble & ref_result(); // 6 wibble * ptr_result(); // 7
wibble value; // 8 wibble & ref; // 9 wibble * ptr; // 10
static wibble shared_value; // 11 static wibble & shared_ptr; // 12 static wibble * shared_ptr; // 13};
we'll see how you all did shortly!
#include in .hpp .cpp
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"#include "snafu.hpp"#include "widget.hpp"
class fubar { ...};
#endif
#include "fubar.hpp"
...
fubar.hpp client.cpp
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
class snafu;class widget;
class fubar { ...};
#endif
#include "fubar.hpp"#include "snafu.hpp"#include "widget.hpp"
...
fubar.hpp client.cpp
• compile times down• physical coupling down• happiness up
#include in .hpp .cpp
how much does a #include cost?
#include <string>
includer.cpp
$ g++ -H includer.cpp &> lines$ wc -l lines
how much does a #include cost?
#include <string>
includer.cpp
$ g++ -H includer.cpp &> lines$ wc -l lines
. /usr/include/c++/4.2.1/string
.. /usr/include/c++/4.2.1/bits/c++config.h
... /usr/include/c++/4.2.1/bits/os_defines.h
.... /usr/include/unistd.h
..... /usr/include/_types.h
...... /usr/include/sys/_types.h
....... /usr/include/sys/cdefs.h
........ /usr/include/sys/_symbol_aliasing.h
........ /usr/include/sys/_posix_availability.h
....... /usr/include/machine/_types.h
........ /usr/include/i386/_types.h
..... /usr/include/sys/unistd.h
...... /usr/include/sys/cdefs.h ... ... ...... /usr/include/c++/4.2.1/bits/stl_uninitialized.h... /usr/include/c++/4.2.1/bits/stl_algo.h.... /usr/include/c++/4.2.1/bits/stl_heap.h..... /usr/include/c++/4.2.1/debug/debug.h.... /usr/include/c++/4.2.1/bits/stl_tempbuf.h..... /usr/include/c++/4.2.1/memory.... /usr/include/c++/4.2.1/debug/debug.h.. /usr/include/c++/4.2.1/bits/basic_string.tcc
how much does a #include cost?
#include <string>
includer.cpp
$ g++ -H includer.cpp &> lines$ wc -l lines
. /usr/include/c++/4.2.1/string
.. /usr/include/c++/4.2.1/bits/c++config.h
... /usr/include/c++/4.2.1/bits/os_defines.h
.... /usr/include/unistd.h
..... /usr/include/_types.h
...... /usr/include/sys/_types.h
....... /usr/include/sys/cdefs.h
........ /usr/include/sys/_symbol_aliasing.h
........ /usr/include/sys/_posix_availability.h
....... /usr/include/machine/_types.h
........ /usr/include/i386/_types.h
..... /usr/include/sys/unistd.h
...... /usr/include/sys/cdefs.h ... ... ...... /usr/include/c++/4.2.1/bits/stl_uninitialized.h... /usr/include/c++/4.2.1/bits/stl_algo.h.... /usr/include/c++/4.2.1/bits/stl_heap.h..... /usr/include/c++/4.2.1/debug/debug.h.... /usr/include/c++/4.2.1/bits/stl_tempbuf.h..... /usr/include/c++/4.2.1/memory.... /usr/include/c++/4.2.1/debug/debug.h.. /usr/include/c++/4.2.1/bits/basic_string.tcc
$ g++ -H includer.cpp &> lines$ wc -l lines 244 lines
you must not tell lies!
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
class snafu;class widget;
class fubar { ...};
#endif
namespace fishing{ class snafu { ... };}
fubar.hppfishing/snafu.hpp
namespace fishing{ class widget { ... };}
fishing/widget.hpp
you must not tell lies!
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
namespace fishing{ class snafu; class widget;}
class fubar { ...};
#endif
fubar.hppnamespace fishing{ class snafu { ... };}
fishing/snafu.hpp
namespace fishing{ class widget { ... };}
fishing/widget.hpp
you must not tell lies!
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
namespace std{ class string;}
class fubar { ...};
#endif
namespace std{ class string { ... };}
fubar.hpp <string>
it's not like this!
you must not tell lies!
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
namespace std{ class string;}
class fubar { ...};
#endif
namespace std{ template<typename T> class basic_string { ... };
typedef basic_string<char> string; ...
}
fubar.hpp <string>
it's a bit like this!
you must not tell lies!
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
namespace std{ template<typename T> class basic_string;
typdef basic_string<char> string;}
class fubar { ...};
#endif
namespace std{ template<typename T> class basic_string { ... };
typedef basic_string<char> string; ...
}
fubar.hpp <string>
??
you must not tell lies!
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
namespace std{ template<typename T> class basic_string;
typdef basic_string<char> string;}
class fubar{ ...};
#endif
namespace std{ template<typename T1, typename T2 = ..., typename T3 = ...> class basic_string { ... };
typedef basic_string<char> string; ...
}
fubar.hpp <string>default template types
don't forward declare anything in std::
template
#ifndef SNAFU_INCLUDED#define SNAFU_INCLUDED
#include <algorithm>...
template<typename T>class snafu{public: void reserve(int limit) { std::for_each(...) } ...};
#endif
snafu.hpp
templates canincreasecoupling
template
#ifndef SNAFU_INCLUDED#define SNAFU_INCLUDED
...
template<typename T>class snafu{public: void reserve(int limit); ...};
#include "snafu-template.hpp"
#endif
#include <algorithm>
template<typename T>void snafu<T>::reserve(int limit){ std::for_each(...)}
...
snafu.hpp snafu-template.hpp
templates canincreasecoupling
inline
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include <vector>
class fubar{public: typedef std::vector<int>::iterator iterator;
void algo(iterator from, iterator to) { ... } ...};
inlining usually increases coupling
fubar.hpp
template
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
...
class fubar{public: template<typename iterator> void algo(iterator from, iterator to) { ... } ...};
#endif
#include "fubar.hpp"#include <vector>
void eg(std::vector<int> & v){ fubar f; f.algo(v.begin(), v.end());}
fubar.hppexample.cpp
templates canalso decrease
coupling!
does this compile?
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
class fubar{public: ... void fu(); ...private: std::vector<wibble> wibbles;};
#endif
#include <vector>#include "fubar.hpp"
void fubar::fu(){ ...}
fubar.hpp fubar.cpp
does this compile?
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
class fubar{public: ... void fu(); ...private: std::vector<wibble> wibbles;};
#endif
#include <vector>#include "fubar.hpp"
void fubar::fu(){ ...}
fubar.hpp fubar.cpp
yes
does this compile?
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
class fubar{public: ... void fu(); ...private: std::vector<wibble> wibbles;};
#endif
#include "fubar.hpp"#include <vector>
void fubar::fu(){ ...}
fubar.hpp fubar.cpp
does this compile?
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
class fubar{public: ... void fu(); ...private: std::vector<wibble> wibbles;};
#endif
#include "fubar.hpp"#include <vector>
void fubar::fu(){ ...}
fubar.hpp fubar.cpp
no
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"
class fubar{public: ... void fu(); ...private: std::vector<wibble> wibbles;};
#endif
#include "fubar.hpp"#include <vector>
void fubar::fu(){ ...}
fubar.hpp fubar.cpp
does this compile?
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"#include <vector>
class fubar{public: ... void fu(); ...private: std::vector<wibble> wibbles;};
#endif
#include "fubar.hpp"...
void fubar::fu(){ ...}
fubar.hpp fubar.cpp
does this compile?
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"#include <vector>
class fubar{public: ... void fu(); ...private: std::vector<wibble> wibbles;};
#endif
#include "fubar.hpp"...
void fubar::fu(){ ...}
fubar.hpp fubar.cpp
yes
include your own header 1st
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"#include <vector>
class fubar{public: ... void fu(); ...private: std::vector<wibble> wibbles;};
#endif
#include "fubar.hpp"...
void fubar::fu(){ ...}
fubar.hpp fubar.cpp
better still - make sure each header compiles (on its own) as
part of the build!
#ifndef FUBAR_INCLUDED#define FUBAR_INCLUDED
#include "wibble.hpp"#include <vector>
class fubar{public: ... void fu(); ...private: std::vector<wibble> wibbles;};
#endif
fubar.hpp
remember this...
#include "wibble.hpp"
class fubar : public wibble // 1{ void value_parameter(wibble ); // 2 void ref_parameter(wibble &); // 3 void ptr_parameter(wibble *); // 4
wibble value_result(); // 5 wibble & ref_result(); // 6 wibble * ptr_result(); // 7
wibble value; // 8 wibble & ref; // 9 wibble * ptr; // 10
static wibble shared_value; // 11};
the answer is...
#include "wibble.hpp"
class fubar : public wibble // 1{ void value_parameter(wibble ); // 2 void ref_parameter(wibble &); // 3 void ptr_parameter(wibble *); // 4
wibble value_result(); // 5 wibble & ref_result(); // 6 wibble * ptr_result(); // 7
wibble value; // 8 wibble & ref; // 9 wibble * ptr; // 10
static wibble shared_value; // 11};
how did you all do?
over to my assistant...
the Satir change curve
old status quo
new status quo old status quo
foreign element
resistance and chaosin
tegr
atio
n an
d pr
acti
cetime
com
pete
nce