|
|
Line 113: |
Line 113: |
| Now you should have build+run debug+release configurations, selectable in the weird project icon in bottom of left-side toolbar ("mode selector") | | 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" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! c++ in-memory storage of "major" objects | | ! c++ in-memory storage of "major" objects |
Line 508: |
Line 218: |
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! C++ | | ! c++11 |
| |- | | |- |
| | | | | |
| {| 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" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! c++11 include base constructor (etc) in derived class | | ! c++11 include base constructor (etc) in derived class |
Line 840: |
Line 473: |
| SP_COUNT | | SP_COUNT |
| } STRING_PREF_INDEX; | | } 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 947: |
Line 483: |
| --> | | --> |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! C++ | | ! boost |
| |- | | |- |
| | | | | |
| {| 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" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! boost release and debug build for linux | | ! boost release and debug build for linux |
Line 1,028: |
Line 523: |
| |} | | |} |
| {| class="mw-collapsible mw-collapsed wikitable" | | {| class="mw-collapsible mw-collapsed wikitable" |
| ! c++11 include base constructor (etc) in derived class | | ! boost regex (very similar to c++11, with LESS BUGS and MORE POWER) |
| |-
| |
| | 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: | | | boost regex does everything you could need, take your time to get it right |
| TODO
| | * regex_search will work hard to find substrings, while regex_match requires your regex to match entire input |
| |}
| | * smatch is a great way to get back a bunch of iterators to the results |
| | | example: |
| {| class="mw-collapsible mw-collapsed wikitable"
| | virtual bool url_upgrade_any_old_semver(string& url) |
| ! 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;
| | // Perform a regex to update the embedded version if needed. |
| return 0;
| | // We have to see if (1) we have a semver and (2) it is not the current semver. |
| | // Only then do we take action. |
| | boost::regex regex("/([v0-9.]+?)/(.*)"); |
| | boost::smatch sm_res; |
| | if (boost::regex_match(url,sm_res,regex,boost::match_default)) |
| | { |
| | string incoming_semver(sm_res[1].first,sm_res[1].second); |
| | if (incoming_semver != semanticVersion()) |
| | { |
| | url = string("/")+semanticVersion()+"/"+string(sm_res[2].first,sm_res[2].second); |
| | return true; |
| | } |
| | } |
| | return false; |
| } | | } |
| in.seekg(0,std::ios::end);
| | results: |
| unsigned long length = in.tellg();
| | original string: string(sm_res[0].first,sm_res[0].second); |
| in.seekg(0,std::ios::beg);
| | first group: string(sm_res[1].first,sm_res[1].second); |
|
| | second group: string(sm_res[2].first,sm_res[2].second); |
| string str(length,0);
| | etc. |
| 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?)
| |
| |} | | |} |
| |} | | |} |