Development reference: Difference between revisions
No edit summary |
No edit summary |
||
Line 499: | Line 499: | ||
** windows: Qt Creator (OR Visual Studio OR eclipse?) | ** windows: Qt Creator (OR Visual Studio OR eclipse?) | ||
|} | |} | ||
|} | |||
<!-- | |||
=========================================================================================================================================================================================================================================================================================== | |||
--> | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! C++ | |||
|- | |||
| | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Deleting multiple elements in a collection | |||
|- | |||
| | |||
* For sequences (vector, list...), best practice is to use the [https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom erase-remove] STL pattern | |||
* For associative containers (set, map...): just recurse and remove iterators, they won't muck up the sequence. [http://stackoverflow.com/questions/800955/remove-if-equivalent-for-stdmap example] | |||
See MemoryModel::saveDirtyObjectsAsNeeded() for example code. | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++ Create a portable C/C++ project | |||
|- | |||
| Use QtCreator + CMake, both available everywhere! | |||
set up: | |||
create a Qt project as: New Project-> Non-Qt/Plain C Project (CMake Build) | |||
pick the PARENT and use the name of the existing folder | |||
set up a build folder in the existing folder, called (base)/qtcreator-release-build | |||
it creates CMakeLists.txt (THIS IS BASICALLY THE PROJECT FILE!) | |||
also creates main.c or something | |||
build it! make sure it works | |||
NOW we can edit CMakeLists.txt - change . to ./src to get it to scan the src folder for code! | |||
and easily add "known" libs! this was all i needed: | |||
TARGET_LINK_LIBRARIES(${PROJECT_NAME} pthread websockets) | |||
make sure it builds | |||
now we want a DEBUG build as well! | |||
Projects->Build&Run->pick Build in weird Build/Run pillbox->Edit build configs: | |||
Rename: release | |||
CMake build dir: Make sure build dir is set to release ie qtcreator-debug-build | |||
Add: Clone: release, name: debug | |||
for debug, add a custom build step BEFORE make step: | |||
command: /usr/bin/cmake | |||
args: -DCMAKE_BUILD_TYPE=Debug . | |||
working dir: %{buildDir} | |||
(add it, and move it up above make) | |||
(build em both) | |||
Projects->Build&Run->pick Run in weird Build/Run pillbox | |||
Run Configuration: rename to "{...} release" | |||
clone it into "{...} debug" | |||
change working dir to match Build path | |||
change any needed params | |||
Now you should have build+run debug+release configurations, selectable in the weird project icon in bottom of left-side toolbar ("mode selector") | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! boost release and debug build for linux | |||
|- | |||
| | |||
# download latest boost, eg: boost_1_59_0 | |||
m@wallee:~/development$ 7z x boost_1_59_0.7z | |||
cd boost_1_##_0 | |||
build_boost_release_and_debug.sh | |||
# then patch .bashrc as instructed | |||
# eclipse and server/nix/bootstrap.sh are customized to match | |||
To upgrade a project: | |||
cd nix | |||
make distclean # removes nasty .deps folders that link to old boost if you let them | |||
make clean # removes .o files etc | |||
cd ../build-Release && make distclean && make clean | |||
cd ../build-Debug && make distclean && make clean | |||
cd .. | |||
./bootstrap force release | |||
./bootstrap force debug | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! boost release and debug build for Windows | |||
|- | |||
| Open a VS2015 x64 Native Tools Command Prompt. | |||
EITHER: for new installs, you have to run bootstrap.bat first, it will build b2; | |||
OR: for reruns, remove boost dirs: [bin.v2, stage]. | |||
Then build 64-bit: | |||
cd "....\boost_1_59_0" | |||
b2 toolset=msvc variant=release,debug link=static address-model=64 | |||
rem trying to avoid excessive options, assuming I don't need these: threading=multi | |||
(old stuff) | |||
--toolset=msvc-14.0 address-model=64 --build-type=complete --stagedir=windows_lib\x64 stage | |||
Now open VS2013 x86 Native Tools Command Prompt and build 32-bit: | |||
cd "C:\Michael's Data\development\sixth_column\boost_1_55_0" | |||
bjam --toolset=msvc-12.0 address-model=32 --build-type=complete --stagedir=windows_lib\x86 stage | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 include base constructor (etc) in derived class | |||
|- | |||
| The awesome C++11 way to steal the constructor from the base class, oh man I've been waiting for this one... | |||
class HttpsServer : public Server<HTTPS> | |||
{ | |||
// DOES THIS FOR YOU! | |||
/* | |||
HttpsServer(unsigned short port, size_t num_threads, const std::string& cert_file, const std::string& private_key_file) | |||
: | |||
// Call base class | |||
Server<HTTPS>::Server(port, num_threads, cert_file, private_key_file) | |||
{} | |||
*/ | |||
using Server<HTTPS>::Server; | |||
.... | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 containers | |||
|- | |||
| sorted_vector || use when doing lots of unsorted insertions and maintaining constant sort would be expensive; vector is good for a big pile of things that only occasionally needs a sorted lookup | |||
|- | |||
| map || sorted binary search tree; always sorted by key; you can walk through in sorted order (choose unordered if not needed!) | |||
|- | |||
| multimap || same as map but allows dupe keys (not as common) | |||
|- | |||
| unordered_map || hashmap; always sorted by key; additional bucket required for hash collisions; no defined order when walking through | |||
|- | |||
| unordered_multimap || same as map but allows dupe keys; dupes are obviously in the same bucket, and you can walk just the dupes if needed | |||
|- | |||
| set<br>multiset<br>unordered_set<br>unordered_multiset || sets are just like maps, except the key is embedded in the object, nice for encapsulation.<br /> | |||
Items must be const (!) since they are the key - sounds bad, but this is mitigated by the mutable keyword.<br /> | |||
You can use mutable on the variables that are not part of the key to remove the const.<br /> | |||
This changes the constness of the object from binary (completely const) to logical (constness is defined by the developer).<br /> | |||
So... set is a good way to achieve both encapsulation and logical const - make const work for you, not against! :-)<br /> | |||
|- | |||
| set (etc.) of pointers || sets of pointers are the pinnacle of object stores<br /> | |||
The entire object can be dereferenced and accessed then without const issues.<br /> | |||
A pointer functor can be provided that does a sort by dereferencing the pointer to the object.<br /> | |||
Two requirements: you must make sure yourself that you do not change the key values - you can mark them const, provided in constructor;<br /> | |||
you must create sort/equal/hash functors that dereference the pointers to use object contents<br /> | |||
(the default will be by pointer address).<br /> | |||
The arguably biggest advantage, as a result, is that you can create multiple sets<br /> | |||
to reference the same group of objects with different sort funtors to create multiple indices.<br /> | |||
You just have to manage the keys carefully, so that they don't change (which would invalidate the sorting).<br /> | |||
The primary container can manage object allocation; using a heap-based unique_ptr allocation<br /> | |||
map vs key redux | |||
use a key in the set, derive a class from it with the contents | |||
+ small key | |||
+ encapsulation | |||
- requires mutable to solve the const problem | |||
use a key in the set, key includes a mutable object | |||
+ encapsulation | |||
- weird bc everything uses a const object but we have const functions like save() that change the mutable subobject | |||
use a map | |||
+ small key | |||
- no encapsulation, have to deal with a pair instead of an object | |||
can we just put a ref to key in the value? sure why not - err, bc we don't have access to it | |||
+ solves const problem bc value is totally mutable by design | |||
+ we can have multiple keys - and the value can have multiple refs to them | |||
+ simpler equal and hash functions | |||
map: | |||
create an object with internal key(s) | |||
create map index(es) with duplicate key values outside the object - dupe data is the downside | |||
use set(s) with one static key for find(): | |||
create an object with internal key(s) | |||
create set index(es) with specific hash/equals functor(s) | |||
when finding, use one static key object (even across indexes!) so there isn't a big construction each time; just set the necessary key values | |||
that proves difficult when dealing with member vars that are references | |||
but to solve it, just set up a structure of dummy static key objects that use each other; then provide a function to setKey(Object& keyref) { keyref_ = keyref; } | |||
nope, can't reassign refs | |||
the solution: use pointers not references | |||
yes that's right | |||
just do it | |||
apparently there was a reason i was anti-reference for all those years | |||
two reasons to use pointers: | |||
dynamically allocated | |||
reassignment required | |||
there ya go. simple. get it done. | |||
when accessing find results from the set, use a const_cast on the object! | |||
WARNING: a separate base class with the key sounds good... but fails when you have more than one index on the object. just use a static key object for them all! | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example for large groups of objects with frequent crud AND search | |||
|- | |||
| Best solution is an unordered set of pointers: | |||
typedef boost::unordered_set<MajorObject*> MajorObjects; | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example for large groups of objects with infrequent crud and frequent search | |||
|- | |||
| Best solution is a vector of pointers sorted on demand (sorted_vector): | |||
TODO | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example to associate two complex objects (one the map key, one the map value) | |||
|- | |||
| Use unordered_map with a custom object as key. You must add hash and equals functions. Boost makes it easy: | |||
static bool operator==(MyKeyObject const& m1, MyKeyObject const& m2) | |||
{ | |||
return | |||
m1.id_0 == m2.id_0 | |||
&& m1.id_1 == m2.id_1; | |||
} | |||
static std::size_t hash_value(MyKeyObject const& mko) | |||
{ | |||
std::size_t seed = 0; | |||
boost::hash_combine(seed, mko.id_0); | |||
boost::hash_combine(seed, mko.id_1); | |||
return seed; | |||
} | |||
typedef boost::unordered_map<MyKeyObject, MyValueObject*> MyMap; | |||
Note that you can extend this to use a pointer to a key object, whoop. | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example for multiple unordered_set indexes into one group of objects | |||
|- | |||
| Objects will be dynamically created. One set should include them all and be responsible for memory allocation cleanup: | |||
TODO | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example for set with specific sorting | |||
|- | |||
| Use set with a specific sort functor. You can create as many of these indexes as you want! | |||
struct customers_set_sort_functor | |||
{ | |||
bool operator()(const MyObject* l, const MyObject* r) const | |||
{ | |||
// the id is the key | |||
return l->id_ < r->id_; | |||
} | |||
}; | |||
typedef set<MyObject*,myobject_sort_by_id_functor> MyObjectsById; | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 loop through vector to erase some items | |||
|- | |||
| Note that other containers' iterators may not be invalidated so you can just erase() as needed... | |||
For vectors, you have to play with iterators to get it right - watch for proper ++ pre/postfix! | |||
for (it = numbers.begin(); it != numbers.end(); ) // NOTE we increment below, only if we don't erase | |||
{ | |||
if (*it.no_good()) | |||
{ | |||
numbers.erase(it++); // NOTE that we ERASE THEN INCREMENT here. | |||
} | |||
else | |||
{ | |||
++it; | |||
} | |||
} | |||
I thought I had always looped backwards to do this, I *think* that's ok too, but I don't see it used in my code, I think I'll avoid. :-) | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 range based for loop, jacked with boost index if needed | |||
|- | |||
| No iterator usage at all. Nice at times, not enough at others. Make SURE to always use a reference or you will be working on a COPY. Make it const if you aren't changing the object. | |||
for (auto& mc : my_container) | |||
mc.setString("default"); | |||
for (const auto& cmc : my_container) | |||
cout << cmc.asString(); | |||
boost index can give you the index if you need it, sweet: | |||
#include <boost/range/adaptor/indexed.hpp> | |||
... | |||
for (const auto &element: boost::adaptors::index(mah_container)) | |||
cout << element.value() << element.index(); | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 for loop using lambda | |||
|- | |||
| This C++11 for loop is clean and elegant and a perfect way to check if your compiler is ready for c++11: | |||
vector<int> v; | |||
for_each( v.begin(), v.end(), [] (int val) | |||
{ | |||
cout << val; | |||
} ); | |||
This is using a lambda function, we should switch from iterators and functors to those - but not quite yet, since we're writing cross-platform code. Do not touch this until we can be sure that all platforms provide compatible C++11 handling. | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 integer types | |||
|- | |||
| I really like the "fast" C++11 types, that give best performance for a guaranteed minimum bit width. | |||
Use them when you know a variable will not exceed the maximum value of that bit width, but does not have to be a precise bit width in memory or elsewhere. | |||
Pick specific-width fields whenever data is shared with other processes and components and you want a guarantee of its bit width. | |||
And when using pointer size and array indices you should use types defined for those specific situations. | |||
FAST types: | |||
int_fast8_t | |||
int_fast16_t fastest signed integer type with width of | |||
int_fast32_t at least 8, 16, 32 and 64 bits respectively | |||
int_fast64_t | |||
uint_fast8_t | |||
uint_fast16_t fastest unsigned integer type with width of | |||
uint_fast32_t at least 8, 16, 32 and 64 bits respectively | |||
uint_fast64_t | |||
SMALL types: | |||
int_least8_t | |||
int_least16_t smallest signed integer type with width of | |||
int_least32_t at least 8, 16, 32 and 64 bits respectively | |||
int_least64_t | |||
uint_least8_t | |||
uint_least16_t smallest unsigned integer type with width of | |||
uint_least32_t at least 8, 16, 32 and 64 bits respectively | |||
uint_least64_t | |||
EXACT types: | |||
int8_t signed integer type with width of | |||
int16_t exactly 8, 16, 32 and 64 bits respectively | |||
int32_t with no padding bits and using 2's complement for negative values | |||
int64_t (provided only if the implementation directly supports the type) | |||
uint8_t unsigned integer type with width of | |||
uint16_t exactly 8, 16, 32 and 64 bits respectively | |||
uint32_t (provided only if the implementation directly supports the type) | |||
uint64_t | |||
SPECIFIC-USE types: | |||
intptr_t integer type capable of holding a pointer | |||
uintptr_t unsigned integer type capable of holding a pointer | |||
size_t unsigned integer type capable of holding an array index (same size as uintptr_t) | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! C++11 scoped enumeration | |||
|- | |||
| C++11 has scoped enumeration, which lets you specify the SPECIFIC VARIABLE TYPE for the enum. Perfect, let's use uint_fast32_t. | |||
enum class STRING_PREF_INDEX int_fast32_t: { ... }; | |||
Unfortunately, gcc gives me a scary warning, and stuff fails. For some reason, it does not know about the provided type, although it is definitely defined. Revisit this later if you have time. | |||
warning: elaborated-type-specifier for a scoped enum must not use the ‘class’ keyword | |||
Old skool is still cool: | |||
typedef enum | |||
{ | |||
// assert( SP_COUNT == 2 ); | |||
SP_FIRST = 0 , | |||
SP_SOME_PREF = SP_FIRST , | |||
SP_ANOTHA , | |||
SP_COUNT | |||
} STRING_PREF_INDEX; | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++ in-memory storage of "major" objects | |||
|- | |||
| | |||
OBSERVATION ONE | |||
Consider An Important Qt Design: QObjects cannot normally be copied | |||
their copy constructors and assignment operators are private | |||
why? A Qt Object... | |||
might have a unique QObject::objectName(). If we copy a Qt Object, what name should we give the copy? | |||
has a location in an object hierarchy. If we copy a Qt Object, where should the copy be located? | |||
can be connected to other Qt Objects to emit signals to them or to receive signals emitted by them. If we copy a Qt Object, how should we transfer these connections to the copy? | |||
can have new properties added to it at runtime that are not declared in the C++ class. If we copy a Qt Object, should the copy include the properties that were added to the original? | |||
in other words, a QObject is a pretty serious object that has the ability to be tied to other objects and resources in ways that make copying dangerous | |||
isn't this true of all serious objects? pretty much | |||
OBSERVATION TWO | |||
if you have a vector of objects, you often want to track them individually outside the vector | |||
if you use a vector of pointers, you can move the object around much more cheaply, and not worry about costly large vector reallocations | |||
a vector of objects (not pointers) only makes sense if the number of objects is initially known and does not change over time | |||
OBSERVATION THREE | |||
STL vectors can store your pointers, iterate thru them, etc. | |||
for a vector of any substantial size, you want to keep objects sorted so you can find them quickly | |||
that's what my sorted_vector class is for; it simply bolts vector together with sort calls and a b_sorted status | |||
following STL practices, to get sorting, you have to provide operator< for whatever is in your vector | |||
BUT... you are not allowed to do operator<(const MyObjectPtr* right) because it would require a reference to a pointer which is not allowed | |||
BUT... you can provide a FUNCTOR to do the job, then provide it when sorting/searching | |||
a functor is basically a structure with a bool operator()(const MyObjectPtr* left, const MyObjectPtr* right) | |||
OBSERVATION FOUR | |||
unordered_set works even better when combining frequent CRUD with frequent lookups | |||
SUMMARY | |||
Dealing with tons of objects is par for the course in any significant app. | |||
Finding a needle in the haystack of those objects is also standard fare. | |||
Having multiple indices into those objects is also essential. | |||
Using unordered_set with object pointers and is very powerful. | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++ stl reverse iterator skeleton | |||
|- | |||
| From [http://www.sgi.com/tech/stl/ReverseIterator.html SGI]... | |||
reverse_iterator rfirst(V.end()); | |||
reverse_iterator rlast(V.begin()); | |||
while (rfirst != rlast) | |||
{ | |||
cout << *rfirst << endl; | |||
... | |||
rfirst++; | |||
} | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++ stl reading a binary file into a string | |||
|- | |||
| | |||
std::ifstream in("my.zip",std::ios::binary); | |||
if (!in) | |||
{ | |||
std::cout << "problem with file open" << std::endl; | |||
return 0; | |||
} | |||
in.seekg(0,std::ios::end); | |||
unsigned long length = in.tellg(); | |||
in.seekg(0,std::ios::beg); | |||
string str(length,0); | |||
std::copy( | |||
std::istreambuf_iterator< char >(in) , | |||
std::istreambuf_iterator< char >() , | |||
str.begin() | |||
); | |||
For more, see [[Reading a binary file|c++ stl reading a binary file]] | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! C/C++ best-in-class tool selection | |||
|- | |||
| I need to have easy setup of debug-level tool support for portable C++11 code. And I need to decide and stick to it to be efficient. | |||
* '''Compiler selection''' | |||
** linux and mac: gcc | |||
** windows: Visual Studio | |||
* '''IDE selection''' | |||
** linux and mac: Qt Creator | |||
** windows: Qt Creator (OR Visual Studio OR eclipse?) | |||
* '''Debugger selection''' | |||
** linux and mac: Qt Creator | |||
** windows: Qt Creator (OR Visual Studio OR eclipse?) | |||
|} | |||
|} | |||
<!-- | |||
=========================================================================================================================================================================================================================================================================================== | |||
--> | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! C++ | |||
|- | |||
| | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Deleting multiple elements in a collection | |||
|- | |||
| | |||
* For sequences (vector, list...), best practice is to use the [https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom erase-remove] STL pattern | |||
* For associative containers (set, map...): just recurse and remove iterators, they won't muck up the sequence. [http://stackoverflow.com/questions/800955/remove-if-equivalent-for-stdmap example] | |||
See MemoryModel::saveDirtyObjectsAsNeeded() for example code. | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++ Create a portable C/C++ project | |||
|- | |||
| Use QtCreator + CMake, both available everywhere! | |||
set up: | |||
create a Qt project as: New Project-> Non-Qt/Plain C Project (CMake Build) | |||
pick the PARENT and use the name of the existing folder | |||
set up a build folder in the existing folder, called (base)/qtcreator-release-build | |||
it creates CMakeLists.txt (THIS IS BASICALLY THE PROJECT FILE!) | |||
also creates main.c or something | |||
build it! make sure it works | |||
NOW we can edit CMakeLists.txt - change . to ./src to get it to scan the src folder for code! | |||
and easily add "known" libs! this was all i needed: | |||
TARGET_LINK_LIBRARIES(${PROJECT_NAME} pthread websockets) | |||
make sure it builds | |||
now we want a DEBUG build as well! | |||
Projects->Build&Run->pick Build in weird Build/Run pillbox->Edit build configs: | |||
Rename: release | |||
CMake build dir: Make sure build dir is set to release ie qtcreator-debug-build | |||
Add: Clone: release, name: debug | |||
for debug, add a custom build step BEFORE make step: | |||
command: /usr/bin/cmake | |||
args: -DCMAKE_BUILD_TYPE=Debug . | |||
working dir: %{buildDir} | |||
(add it, and move it up above make) | |||
(build em both) | |||
Projects->Build&Run->pick Run in weird Build/Run pillbox | |||
Run Configuration: rename to "{...} release" | |||
clone it into "{...} debug" | |||
change working dir to match Build path | |||
change any needed params | |||
Now you should have build+run debug+release configurations, selectable in the weird project icon in bottom of left-side toolbar ("mode selector") | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! boost release and debug build for linux | |||
|- | |||
| | |||
# download latest boost, eg: boost_1_59_0 | |||
m@wallee:~/development$ 7z x boost_1_59_0.7z | |||
cd boost_1_##_0 | |||
build_boost_release_and_debug.sh | |||
# then patch .bashrc as instructed | |||
# eclipse and server/nix/bootstrap.sh are customized to match | |||
To upgrade a project: | |||
cd nix | |||
make distclean # removes nasty .deps folders that link to old boost if you let them | |||
make clean # removes .o files etc | |||
cd ../build-Release && make distclean && make clean | |||
cd ../build-Debug && make distclean && make clean | |||
cd .. | |||
./bootstrap force release | |||
./bootstrap force debug | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! boost release and debug build for Windows | |||
|- | |||
| Open a VS2015 x64 Native Tools Command Prompt. | |||
EITHER: for new installs, you have to run bootstrap.bat first, it will build b2; | |||
OR: for reruns, remove boost dirs: [bin.v2, stage]. | |||
Then build 64-bit: | |||
cd "....\boost_1_59_0" | |||
b2 toolset=msvc variant=release,debug link=static address-model=64 | |||
rem trying to avoid excessive options, assuming I don't need these: threading=multi | |||
(old stuff) | |||
--toolset=msvc-14.0 address-model=64 --build-type=complete --stagedir=windows_lib\x64 stage | |||
Now open VS2013 x86 Native Tools Command Prompt and build 32-bit: | |||
cd "C:\Michael's Data\development\sixth_column\boost_1_55_0" | |||
bjam --toolset=msvc-12.0 address-model=32 --build-type=complete --stagedir=windows_lib\x86 stage | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 include base constructor (etc) in derived class | |||
|- | |||
| The awesome C++11 way to steal the constructor from the base class, oh man I've been waiting for this one... | |||
class HttpsServer : public Server<HTTPS> | |||
{ | |||
// DOES THIS FOR YOU! | |||
/* | |||
HttpsServer(unsigned short port, size_t num_threads, const std::string& cert_file, const std::string& private_key_file) | |||
: | |||
// Call base class | |||
Server<HTTPS>::Server(port, num_threads, cert_file, private_key_file) | |||
{} | |||
*/ | |||
using Server<HTTPS>::Server; | |||
.... | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 containers | |||
|- | |||
| sorted_vector || use when doing lots of unsorted insertions and maintaining constant sort would be expensive; vector is good for a big pile of things that only occasionally needs a sorted lookup | |||
|- | |||
| map || sorted binary search tree; always sorted by key; you can walk through in sorted order (choose unordered if not needed!) | |||
|- | |||
| multimap || same as map but allows dupe keys (not as common) | |||
|- | |||
| unordered_map || hashmap; always sorted by key; additional bucket required for hash collisions; no defined order when walking through | |||
|- | |||
| unordered_multimap || same as map but allows dupe keys; dupes are obviously in the same bucket, and you can walk just the dupes if needed | |||
|- | |||
| set<br>multiset<br>unordered_set<br>unordered_multiset || sets are just like maps, except the key is embedded in the object, nice for encapsulation.<br /> | |||
Items must be const (!) since they are the key - sounds bad, but this is mitigated by the mutable keyword.<br /> | |||
You can use mutable on the variables that are not part of the key to remove the const.<br /> | |||
This changes the constness of the object from binary (completely const) to logical (constness is defined by the developer).<br /> | |||
So... set is a good way to achieve both encapsulation and logical const - make const work for you, not against! :-)<br /> | |||
|- | |||
| set (etc.) of pointers || sets of pointers are the pinnacle of object stores<br /> | |||
The entire object can be dereferenced and accessed then without const issues.<br /> | |||
A pointer functor can be provided that does a sort by dereferencing the pointer to the object.<br /> | |||
Two requirements: you must make sure yourself that you do not change the key values - you can mark them const, provided in constructor;<br /> | |||
you must create sort/equal/hash functors that dereference the pointers to use object contents<br /> | |||
(the default will be by pointer address).<br /> | |||
The arguably biggest advantage, as a result, is that you can create multiple sets<br /> | |||
to reference the same group of objects with different sort funtors to create multiple indices.<br /> | |||
You just have to manage the keys carefully, so that they don't change (which would invalidate the sorting).<br /> | |||
The primary container can manage object allocation; using a heap-based unique_ptr allocation<br /> | |||
map vs key redux | |||
use a key in the set, derive a class from it with the contents | |||
+ small key | |||
+ encapsulation | |||
- requires mutable to solve the const problem | |||
use a key in the set, key includes a mutable object | |||
+ encapsulation | |||
- weird bc everything uses a const object but we have const functions like save() that change the mutable subobject | |||
use a map | |||
+ small key | |||
- no encapsulation, have to deal with a pair instead of an object | |||
can we just put a ref to key in the value? sure why not - err, bc we don't have access to it | |||
+ solves const problem bc value is totally mutable by design | |||
+ we can have multiple keys - and the value can have multiple refs to them | |||
+ simpler equal and hash functions | |||
map: | |||
create an object with internal key(s) | |||
create map index(es) with duplicate key values outside the object - dupe data is the downside | |||
use set(s) with one static key for find(): | |||
create an object with internal key(s) | |||
create set index(es) with specific hash/equals functor(s) | |||
when finding, use one static key object (even across indexes!) so there isn't a big construction each time; just set the necessary key values | |||
that proves difficult when dealing with member vars that are references | |||
but to solve it, just set up a structure of dummy static key objects that use each other; then provide a function to setKey(Object& keyref) { keyref_ = keyref; } | |||
nope, can't reassign refs | |||
the solution: use pointers not references | |||
yes that's right | |||
just do it | |||
apparently there was a reason i was anti-reference for all those years | |||
two reasons to use pointers: | |||
dynamically allocated | |||
reassignment required | |||
there ya go. simple. get it done. | |||
when accessing find results from the set, use a const_cast on the object! | |||
WARNING: a separate base class with the key sounds good... but fails when you have more than one index on the object. just use a static key object for them all! | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example for large groups of objects with frequent crud AND search | |||
|- | |||
| Best solution is an unordered set of pointers: | |||
typedef boost::unordered_set<MajorObject*> MajorObjects; | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example for large groups of objects with infrequent crud and frequent search | |||
|- | |||
| Best solution is a vector of pointers sorted on demand (sorted_vector): | |||
TODO | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example to associate two complex objects (one the map key, one the map value) | |||
|- | |||
| Use unordered_map with a custom object as key. You must add hash and equals functions. Boost makes it easy: | |||
static bool operator==(MyKeyObject const& m1, MyKeyObject const& m2) | |||
{ | |||
return | |||
m1.id_0 == m2.id_0 | |||
&& m1.id_1 == m2.id_1; | |||
} | |||
static std::size_t hash_value(MyKeyObject const& mko) | |||
{ | |||
std::size_t seed = 0; | |||
boost::hash_combine(seed, mko.id_0); | |||
boost::hash_combine(seed, mko.id_1); | |||
return seed; | |||
} | |||
typedef boost::unordered_map<MyKeyObject, MyValueObject*> MyMap; | |||
Note that you can extend this to use a pointer to a key object, whoop. | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example for multiple unordered_set indexes into one group of objects | |||
|- | |||
| Objects will be dynamically created. One set should include them all and be responsible for memory allocation cleanup: | |||
TODO | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 example for set with specific sorting | |||
|- | |||
| Use set with a specific sort functor. You can create as many of these indexes as you want! | |||
struct customers_set_sort_functor | |||
{ | |||
bool operator()(const MyObject* l, const MyObject* r) const | |||
{ | |||
// the id is the key | |||
return l->id_ < r->id_; | |||
} | |||
}; | |||
typedef set<MyObject*,myobject_sort_by_id_functor> MyObjectsById; | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 loop through vector to erase some items | |||
|- | |||
| Note that other containers' iterators may not be invalidated so you can just erase() as needed... | |||
For vectors, you have to play with iterators to get it right - watch for proper ++ pre/postfix! | |||
for (it = numbers.begin(); it != numbers.end(); ) // NOTE we increment below, only if we don't erase | |||
{ | |||
if (*it.no_good()) | |||
{ | |||
numbers.erase(it++); // NOTE that we ERASE THEN INCREMENT here. | |||
} | |||
else | |||
{ | |||
++it; | |||
} | |||
} | |||
I thought I had always looped backwards to do this, I *think* that's ok too, but I don't see it used in my code, I think I'll avoid. :-) | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 range based for loop, jacked with boost index if needed | |||
|- | |||
| No iterator usage at all. Nice at times, not enough at others. Make SURE to always use a reference or you will be working on a COPY. Make it const if you aren't changing the object. | |||
for (auto& mc : my_container) | |||
mc.setString("default"); | |||
for (const auto& cmc : my_container) | |||
cout << cmc.asString(); | |||
boost index can give you the index if you need it, sweet: | |||
#include <boost/range/adaptor/indexed.hpp> | |||
... | |||
for (const auto &element: boost::adaptors::index(mah_container)) | |||
cout << element.value() << element.index(); | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++11 for loop using lambda | |||
|- | |||
| This C++11 for loop is clean and elegant and a perfect way to check if your compiler is ready for c++11: | |||
vector<int> v; | |||
for_each( v.begin(), v.end(), [] (int val) | |||
{ | |||
cout << val; | |||
} ); | |||
This is using a lambda function, we should switch from iterators and functors to those - but not quite yet, since we're writing cross-platform code. Do not touch this until we can be sure that all platforms provide compatible C++11 handling. | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! c++11 integer types | ||
|- | |||
| I really like the "fast" C++11 types, that give best performance for a guaranteed minimum bit width. | |||
Use them when you know a variable will not exceed the maximum value of that bit width, but does not have to be a precise bit width in memory or elsewhere. | |||
Pick specific-width fields whenever data is shared with other processes and components and you want a guarantee of its bit width. | |||
And when using pointer size and array indices you should use types defined for those specific situations. | |||
FAST types: | |||
int_fast8_t | |||
int_fast16_t fastest signed integer type with width of | |||
int_fast32_t at least 8, 16, 32 and 64 bits respectively | |||
int_fast64_t | |||
uint_fast8_t | |||
uint_fast16_t fastest unsigned integer type with width of | |||
uint_fast32_t at least 8, 16, 32 and 64 bits respectively | |||
uint_fast64_t | |||
SMALL types: | |||
int_least8_t | |||
int_least16_t smallest signed integer type with width of | |||
int_least32_t at least 8, 16, 32 and 64 bits respectively | |||
int_least64_t | |||
uint_least8_t | |||
uint_least16_t smallest unsigned integer type with width of | |||
uint_least32_t at least 8, 16, 32 and 64 bits respectively | |||
uint_least64_t | |||
EXACT types: | |||
int8_t signed integer type with width of | |||
int16_t exactly 8, 16, 32 and 64 bits respectively | |||
int32_t with no padding bits and using 2's complement for negative values | |||
int64_t (provided only if the implementation directly supports the type) | |||
uint8_t unsigned integer type with width of | |||
uint16_t exactly 8, 16, 32 and 64 bits respectively | |||
uint32_t (provided only if the implementation directly supports the type) | |||
uint64_t | |||
SPECIFIC-USE types: | |||
intptr_t integer type capable of holding a pointer | |||
uintptr_t unsigned integer type capable of holding a pointer | |||
size_t unsigned integer type capable of holding an array index (same size as uintptr_t) | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! C++11 scoped enumeration | |||
|- | |- | ||
| C++11 has scoped enumeration, which lets you specify the SPECIFIC VARIABLE TYPE for the enum. Perfect, let's use uint_fast32_t. | |||
enum class STRING_PREF_INDEX int_fast32_t: { ... }; | |||
Unfortunately, gcc gives me a scary warning, and stuff fails. For some reason, it does not know about the provided type, although it is definitely defined. Revisit this later if you have time. | |||
warning: elaborated-type-specifier for a scoped enum must not use the ‘class’ keyword | |||
Old skool is still cool: | |||
typedef enum | |||
{ | |||
// assert( SP_COUNT == 2 ); | |||
SP_FIRST = 0 , | |||
SP_SOME_PREF = SP_FIRST , | |||
SP_ANOTHA , | |||
SP_COUNT | |||
} STRING_PREF_INDEX; | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++ in-memory storage of "major" objects | |||
|- | |||
| | | | ||
OBSERVATION ONE | |||
Consider An Important Qt Design: QObjects cannot normally be copied | |||
their copy constructors and assignment operators are private | |||
why? A Qt Object... | |||
might have a unique QObject::objectName(). If we copy a Qt Object, what name should we give the copy? | |||
has a location in an object hierarchy. If we copy a Qt Object, where should the copy be located? | |||
can be connected to other Qt Objects to emit signals to them or to receive signals emitted by them. If we copy a Qt Object, how should we transfer these connections to the copy? | |||
can have new properties added to it at runtime that are not declared in the C++ class. If we copy a Qt Object, should the copy include the properties that were added to the original? | |||
in other words, a QObject is a pretty serious object that has the ability to be tied to other objects and resources in ways that make copying dangerous | |||
isn't this true of all serious objects? pretty much | |||
OBSERVATION TWO | |||
if you have a vector of objects, you often want to track them individually outside the vector | |||
if you use a vector of pointers, you can move the object around much more cheaply, and not worry about costly large vector reallocations | |||
a vector of objects (not pointers) only makes sense if the number of objects is initially known and does not change over time | |||
OBSERVATION THREE | |||
STL vectors can store your pointers, iterate thru them, etc. | |||
for a vector of any substantial size, you want to keep objects sorted so you can find them quickly | |||
that's what my sorted_vector class is for; it simply bolts vector together with sort calls and a b_sorted status | |||
following STL practices, to get sorting, you have to provide operator< for whatever is in your vector | |||
BUT... you are not allowed to do operator<(const MyObjectPtr* right) because it would require a reference to a pointer which is not allowed | |||
BUT... you can provide a FUNCTOR to do the job, then provide it when sorting/searching | |||
a functor is basically a structure with a bool operator()(const MyObjectPtr* left, const MyObjectPtr* right) | |||
OBSERVATION FOUR | |||
unordered_set works even better when combining frequent CRUD with frequent lookups | |||
SUMMARY | |||
Dealing with tons of objects is par for the course in any significant app. | |||
Finding a needle in the haystack of those objects is also standard fare. | |||
Having multiple indices into those objects is also essential. | |||
Using unordered_set with object pointers and is very powerful. | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++ stl reverse iterator skeleton | |||
|- | |||
| From [http://www.sgi.com/tech/stl/ReverseIterator.html SGI]... | |||
reverse_iterator rfirst(V.end()); | |||
reverse_iterator rlast(V.begin()); | |||
while (rfirst != rlast) | |||
|- | { | ||
| | cout << *rfirst << endl; | ||
... | |||
rfirst++; | |||
} | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c++ stl reading a binary file into a string | |||
|- | |||
| | |||
std::ifstream in("my.zip",std::ios::binary); | |||
if (!in) | |||
{ | |||
std::cout << "problem with file open" << std::endl; | |||
return 0; | |||
} | |||
in.seekg(0,std::ios::end); | |||
unsigned long length = in.tellg(); | |||
in.seekg(0,std::ios::beg); | |||
string str(length,0); | |||
std::copy( | |||
std::istreambuf_iterator< char >(in) , | |||
std::istreambuf_iterator< char >() , | |||
str.begin() | |||
); | |||
For more, see [[Reading a binary file|c++ stl reading a binary file]] | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! C/C++ best-in-class tool selection | |||
|- | |||
| I need to have easy setup of debug-level tool support for portable C++11 code. And I need to decide and stick to it to be efficient. | |||
* '''Compiler selection''' | |||
** linux and mac: gcc | |||
** windows: Visual Studio | |||
* '''IDE selection''' | |||
** linux and mac: Qt Creator | |||
** windows: Qt Creator (OR Visual Studio OR eclipse?) | |||
* '''Debugger selection''' | |||
** linux and mac: Qt Creator | |||
** windows: Qt Creator (OR Visual Studio OR eclipse?) | |||
|} | |} | ||
|} | |} | ||
Line 626: | Line 1,485: | ||
at first i thought this would work: /usr/local/lib | at first i thought this would work: /usr/local/lib | ||
but i did a static build so i needed teh actual exe! COOL | but i did a static build so i needed teh actual exe! COOL | ||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! c/c++ gdb debugging | |||
|- | |||
| | |||
(gdb) help break | |||
Set breakpoint at specified line or function. | |||
Argument may be line number, function name, or "*" and an address. | |||
If line number is specified, break at start of code for that line. | |||
If function is specified, break at start of code for that function. | |||
If an address is specified, break at that exact address. | |||
With no arg, uses current execution address of selected stack frame. | |||
This is useful for breaking on return to a stack frame. | |||
Multiple breakpoints at one place are permitted, and useful if conditional. | |||
Do "help breakpoints" for info on other commands dealing with breakpoints. | |||
|- | |||
| ddd gives you a front end. I need to use it more, compare to other options | |||
|} | |} | ||
|} | |} |
Revision as of 01:41, 8 June 2017
Design, programming and version control.
Patterns | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
C++ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
C++ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
C++ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
C++ libraries |
---|
C/C++ building/linking | ||||
---|---|---|---|---|
|
C/C++ debugging | |||||
---|---|---|---|---|---|
|
C | ||||
---|---|---|---|---|
|
Bootstrap | ||||||||
---|---|---|---|---|---|---|---|---|
|
D3 | ||||
---|---|---|---|---|
|
RESTFul http | ||
---|---|---|
|
Javascript and JQuery | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
Node.js | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
css |
---|
/* class="first second" */ .first.second {} /* class="first" OR class="second" */ .first, .second {} /* class="first second", or class="second", or class="third second", or class="second third" */ .second {} /* apply to any .child at any depth under .parent */ .parent .child {} /* apply to .child if it is DIRECTLY under .parent */ .parent > .child {} |
SQL | ||
---|---|---|
|
Java |
---|
Scala |
---|
PHP | |||
---|---|---|---|
|
git |
---|
misc | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|