C++: Difference between revisions

 
(26 intermediate revisions by the same user not shown)
Line 81: Line 81:
===String===
===String===
<code>#include <string></code><br>
<code>#include <string></code><br>
If you don't need to own the string, prefer to use <code>string_view</code>.


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 189: Line 191:
[https://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html Reference and comparison of different methods]
[https://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html Reference and comparison of different methods]
<syntaxhighlight lang="C++">
<syntaxhighlight lang="C++">
#include <cerrno>
#include <fstream>
#include <fstream>
#include <string>
#include <string>
#include <cerrno>
#include <string_view>


std::string get_file_contents(const std::string &filename)
std::string get_file_contents(std::string_view filename) {
{
   std::ifstream in(filename, std::ios::in | std::ios::binary);
   std::ifstream in(filename, std::ios::in | std::ios::binary);
   if (in.good())
   if (in.good()) {
  {
     std::string contents;
     std::string contents;
     in.seekg(0, std::ios::end);
     in.seekg(0, std::ios::end);
Line 264: Line 265:
Smart pointers were added in C++11.<br>
Smart pointers were added in C++11.<br>
There are 3 types of smart pointers:
There are 3 types of smart pointers:
* <code>unique_ptr</code>
* [https://en.cppreference.com/w/cpp/memory/unique_ptr <code>std::unique_ptr</code>] - one piece of code ''owns'' the memory at any given time.<br>
* <code>shared_ptr</code>
* <code>std::shared_ptr</code> - the memory has multiple owners.
* <code>weak_ptr</code>
* <code>std::weak_ptr</code> - a non-owning reference to a shared_ptr.
Use <code>unique_ptr</code> when one piece of code ''owns'' the memory at any given time.<br>
 
Use <code>shared_ptr</code> when multiple objects need to reference the same thing.<br>
In general, there should be one object owning an object using a <code>unique_ptr</code>. Whenever you pass the value around, other functions should receive the object as a reference making it clear that they do not have ownership of the object. Smart pointers are nullable and assignable similar to regular pointers.
Use <code>weak_ptr</code> to avoid cyclic dependencies which cause issues with reference counting.<br>
 
If you are using C++14 or newer, you should use <code>make_unique</code> or <code>make_shared</code> which will only make one memory allocation for both the object and the pointer rather than two memory allocations.<br>
Prefer to use <code>make_unique</code> or <code>make_shared</code> which will only make one memory allocation for both the object and the pointer rather than two memory allocations.<br>
Alternatively if you already have a smart pointer, you can call <code>my_ptr.reset(new Car())</code> to change the pointer or <code>my_ptr.reset()</code> to deallocate the object referenced by the pointer.
 
You can call <code>my_ptr.reset(new Car())</code> to change the pointer or <code>my_ptr.reset()</code> to deallocate the object referenced by the pointer.
Example:
Example:
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 294: Line 296:
** May throw <code>bad_weak_ptr</code> if you call <code>shared_from_this()</code> without <code>make_shared</code> or if you do not publically inherit <code>std::enable_shared_from_this<T></code>
** May throw <code>bad_weak_ptr</code> if you call <code>shared_from_this()</code> without <code>make_shared</code> or if you do not publically inherit <code>std::enable_shared_from_this<T></code>
* When writing functions when do not operate on pointers and do not claim ownership of objects, you should just take a reference to the object as the argument.
* When writing functions when do not operate on pointers and do not claim ownership of objects, you should just take a reference to the object as the argument.
* <code>std::auto_ptr</code> was a predecessor to <code>std::unique_ptr</code> which allowed copies. It shouldn't be used anymore.


====Garbage Collection====
====Garbage Collection====
Line 417: Line 420:
===Chrono===
===Chrono===
<code>#include <chrono></code><br>
<code>#include <chrono></code><br>
Lots of useful time stuff. Good for timing your code.
 
I now prefer using <code>absl::Time</code> and <code>absl::Duration</code> over Chrono because they abstract away the underlying type.
 
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
auto start = std::chrono::high_resolution_clock::now();
auto start = std::chrono::high_resolution_clock::now();
Line 458: Line 463:
std::cout << '\n';
std::cout << '\n';
</syntaxhighlight>
</syntaxhighlight>
===const===
For variables:
# Use <code>constexpr</code> for values initialized at compile time and won't change at runtime. Most of the time, this is what you want for hardcoded compile time parameters.
# Use <code>const</code> for values initialized at runtime and won't change.
# Use <code>constinit</code> for values initialized at compile time and may change at runtime. I haven't found a use case for this yet.
For functions:
# Add <code>const</code> to the end of a method declaration if it won't change the object.
# Add <code>constexpr</code> if the function can be evaluated at compile time, i.e. can accepts and output <code>constexpr</code> variables.
# Add <code>consteval</code> if you want to force the function to only be evaluated at compile time.


==STL==
==STL==
Line 616: Line 632:
https://medium.com/swlh/doing-it-the-functional-way-in-c-5c392bbdd46a
https://medium.com/swlh/doing-it-the-functional-way-in-c-5c392bbdd46a


Many of these can be parallelized with [https://en.cppreference.com/w/cpp/algorithm/execution_policy_tag_t execution policies] such as <code>std::execution::par</code> and <code>std::execution::par_unseq</code>.
Many of these can be parallelized with [https://en.cppreference.com/w/cpp/algorithm/execution_policy_tag_t execution policies] such as <code>std::execution::par</code> and <code>std::execution::par_unseq</code>. Paired with [https://adaptivecpp.github.io/AdaptiveCpp/stdpar/ AdaptiveCPP], some operations can be automatically GPU accelerated as well.


Most of these require C++20.
Most of these require C++20.


;Map
===Map===
* <code>std::for_each</code>
* <code>std::for_each</code>
* <code>std::transform</code>
* <code>std::transform</code>
* [https://en.cppreference.com/w/cpp/algorithm/copy <code>std::copy</code>, <code>std::copy_if</code>]
* [https://en.cppreference.com/w/cpp/algorithm/fill <code>std::fill</code>]


;Reduce/Fold
===Reduce/Fold===
* <code>std::reduce</code>
* <code>std::accumulate</code>
* <code>std::accumulate</code>
* [https://en.cppreference.com/w/cpp/algorithm/ranges/fold_left <code>std::ranges::fold_left</code>] (C++23)
* [https://en.cppreference.com/w/cpp/algorithm/ranges/fold_left <code>std::ranges::fold_left</code>] (C++23)


;Filter
===Filter===
* <code>std::copy_if</code>
* <code>std::copy_if</code>
* <code>std::remove_if</code>
* <code>std::remove_if</code>
Line 639: Line 658:
** I.e. each object should manage it's own memory rather than the caller having to manage it.
** I.e. each object should manage it's own memory rather than the caller having to manage it.
** You should never use `malloc` and `free` unless interfacing with C libraries.
** You should never use `malloc` and `free` unless interfacing with C libraries.
* Use smart pointers instead of new and delete.
* Avoid the use of new and delete, instead using vector or smart pointers.
** Namely, <code>std::unique_ptr</code>, <code>std::shared_ptr</code>, and <code>std::vector</code>.
* Use clang-format.
* Use clang-format.


Line 649: Line 667:
==RAII==
==RAII==
[https://en.cppreference.com/w/cpp/language/raii cppreference raii]<br>
[https://en.cppreference.com/w/cpp/language/raii cppreference raii]<br>
[https://en.cppreference.com/w/cpp/language/rule_of_three cppreference rule_of_three]<br>
Resource Acquisition Is Initialization - binds the life cycle of a resource to the lifetime of an object.<br>
Resource Acquisition Is Initialization - binds the life cycle of a resource to the lifetime of an object.<br>
For instance, the resource for a vector is an allocated amount of memory. Once the vector is destroyed and the destructor called, the resource is released.<br>
For instance, the resource for a vector is an allocated amount of memory. Once the vector is destroyed and the destructor called, the resource is released.<br>
In general, each RAII object should have all of the following:
 
* Constructor acquiring resources
If you need any from one of the rules, you need to implement the remainder
* Copy Constructor
 
* Assignment operator
;Rule of zero<br>
* Destructor releasing resources
Do not use a custom deconstructor, copy constructor, or copy assignment. Push all of these operations into the classes of member variables such as <code>std::vector</code> and <code>unique_ptr</code>. This is the best and simplest case.
* Swap function (for <code>std::swap</code>)
 
* Move constructor (since C++11, for <code>std::move</code>)
;[[Wikipedia: Rule of three (C++ programming) | Rule of three]]
{{hidden | Example RAII Class |
* Destructor
* Copy constructor
* Copy assignment operator
 
;[[Wikipedia: Rule of three (C++ programming)#Rule of five | Rule of five]]
* All from rule of three plus:
* Move constructor
* Move operator
 
;Rule of four and a half:
* Destructor
* Copy constructor
* Copy-and-swap assignment operator
* Swap function
 
{{hidden | Example Rule of Four RAII Class |
Copied from [https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom stack overflow]
Copied from [https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom stack overflow]
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 691: Line 725:
     }
     }


    // assignment operator
    dumb_array& operator=(dumb_array other) // (1)
    {
        swap(*this, other); // (2)
        return *this;
    }
    // swap
     friend void swap(dumb_array& first, dumb_array& second) // nothrow
     friend void swap(dumb_array& first, dumb_array& second) // nothrow
     {
     {
Line 700: Line 743:
         swap(first.mSize, second.mSize);
         swap(first.mSize, second.mSize);
         swap(first.mArray, second.mArray);
         swap(first.mArray, second.mArray);
    }
    dumb_array& operator=(dumb_array other) // (1)
    {
        swap(*this, other); // (2)
        return *this;
    }
    dumb_array(dumb_array&& other) noexcept ††
        : dumb_array() // initialize via default constructor, C++11 only
    {
        swap(*this, other);
     }
     }


Line 736: Line 766:
{{main | Eigen (C++ library)}}
{{main | Eigen (C++ library)}}
A header-only C++ linear algebra library.
A header-only C++ linear algebra library.
===absl===
https://github.com/abseil/abseil-cpp is a library used by Google which supplements the standard library.
Useful things:
# <code>absl::Time</code> and <code>absl::Duration</code>.
# [https://abseil.io/docs/cpp/guides/strings#abslstrcat absl strings]
# [https://abseil.io/docs/cpp/guides/logging absl logging]
Many parts of absl now have <code>std::</code> equivalents such as <code>std::unique_ptr</code>, <code>std::string_view</code>, <code>std::span</code>. Unless contributing to Google codebases, you should probably prefer those.
At Google, they prefer absl hash containers over unordered_set and unordered_map:
# <code>absl::flat_hash_map</code>


==References==
==References==


[[Category:Programming languages]]
[[Category:Programming languages]]