C++: Difference between revisions

No edit summary
 
(71 intermediate revisions by the same user not shown)
Line 1: Line 1:
__FORCETOC__
__FORCETOC__
C++ is a very popular and powerful language which includes all the low-level features of [[C_(programming_language) | C]] (e.g. pointers, operator overloading) along many high-level features (regex, STL containers) thanks to the C++ standard library.<br>
C++ is a very popular and powerful language which includes all the low-level features of [[C_(programming_language) | C]] (e.g. pointers, operator overloading) along with many high-level features (RAII, STD algorithms, STL containers) thanks to the C++ standard library.
Some people may think of it as an object-oriented version of C.


==Usage==
==Usage==
Line 7: Line 6:
===Compilation===
===Compilation===
{{See also|CMake|Makefile}}
{{See also|CMake|Makefile}}
====cmake====
====g++====
====g++====
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
g++ my_driver.c [-Iincludefolder] -o my_program.out
g++ my_driver.cpp [-Iincludefolder] -o my_program.out
</syntaxhighlight>
</syntaxhighlight>
Misc optimizations
Standard optimizations
* <code>-std=c++17</code> for C++17 support
* <code>-std=c++17</code> for C++17 support
* <code>-O3</code> for level 3 optmizations
* <code>-O3</code> for level 3 optimizations
* <code>-g</code> to include debugging info
* <code>-march=native</code> - use all instructions available on the current CPU
* <code>-mtune=native</code> - optimize for the current CPU


===Syntax===
===Syntax===
====Main====
====Main====
All C++ programs launch in a <code>main</code> function.
All C++ programs launch in a <code>main</code> function.
Similar to [[C]], the arguments are <code>int argc</code> and <code>char *argv[]</code>.<br>
Similar to [[C (programming language) | C]], the arguments are <code>int argc</code> and <code>char *argv[]</code>.<br>
These can be easily converted to a <code>std::vector<std::string></code> for convenience.
These can be easily converted to a <code>std::vector<std::string></code> for convenience.


Line 44: Line 48:
[https://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used Types of casts]
[https://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used Types of casts]


C++ has several types of casts.
C++ has several types of casts including:
These are the main ones you should use.
* [https://en.cppreference.com/w/cpp/language/static_cast <code>static_cast</code>] - your standard cast with conversion. Does not perform any checks.
* <code>static_cast</code>
* [https://en.cppreference.com/w/cpp/language/dynamic_cast <code>dynamic_cast</code>] - for casting objects with checking, requires a polymorphic base class (with a virtual function). Will return nullptr.
* <code>dynamic_cast</code>
* [https://en.cppreference.com/w/cpp/language/reinterpret_cast <code>reinterpret_cast</code>] - cast without any conversion, for directly dealing with binary data, equivalent to <code>*(T*)</code> in C.
If you're casting between things but do not want to change the bit-pattern (e.g. binary data or pointers), you can also use <code>reinterpret_cast</code>.
 
====References====
References are accepted or stored using <code>&</code>.<br>
For example:
<syntaxhighlight lang="c++">
void healPerson(Person &person) {
  person.health = 100;
}
</syntaxhighlight>
References are like pointers since they do not copy the object except they cannot be null and they cannot be reassigned.<br>
Note that primitives can also be used with references, in which case changes will propagate to the underlying value.<br>
You can also use them as class attributes, initializing them in the constructor's initializer list.<br>
To store references in a vector, you can use <code>std::reference_wrapper</code> and include the <code>functional</code> header.
 
====Types====
For simple programs, you can use the standard types:
* <code>int</code>, <code>unsigned int</code>, <code>long</code>, <code>size_t</code>
* <code>float</code>, <code>double</code>
See [https://stackoverflow.com/questions/6462439/whats-the-difference-between-long-long-and-long SO] for the standard and guaranteed precision of these built-in types.
 
C++ also has fixed-width types in <code>#include <cstdint></code> (since C++11).<br>
[https://en.cppreference.com/w/cpp/header/cstdint cppreference cstdint]<br>
I recommend using these for anything with specific or high precision requirements.<br>
Typically, I use:
* <code>uint8_t</code> instead of <code>char</code> or <code>std::byte</code>.<br>
* <code>int64_t</code> instead of <code>long long</code>


===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">
// c-str to string
// c-str to string
char *old_string = "my c-style string";
char *old_string = "my c-style string";
string cpp_string(old_string);
std::string cpp_string(old_string);


// string to c-str
// string to c-str
Line 64: Line 94:
// char to string
// char to string
char my_char = 'a';
char my_char = 'a';
string my_str(1, my_char);
std::string my_str(1, my_char);
</syntaxhighlight>
</syntaxhighlight>


Line 85: Line 115:
</syntaxhighlight>
</syntaxhighlight>


====Buildings Strings====
====Building Strings====
[https://www.fluentcpp.com/2017/12/19/build-strings-from-plain-string-up-to-boost-karma/ The Complete Guide to Building Strings In C++]<br>
[https://www.fluentcpp.com/2017/12/19/build-strings-from-plain-string-up-to-boost-karma/ The Complete Guide to Building Strings In C++]<br>
There are multiple ways of buildings strings in C++.<br>
There are multiple ways of buildings strings in C++.<br>
Strings are mutable in C++.<br>
Strings are mutable in C++.<br>
I typically use <code>+</code> or <code>ostringstream</code> to build strings.
I typically use <code>+</code> or <code>ostringstream</code> to build strings.
====std::basic_string_view====
[https://en.cppreference.com/w/cpp/string/basic_string_view std::basic_string_view]
This is useful for writing functions which accept anything that looks like a string such as substrings, since typically <code>std::string::substr</code> performs a copy.
Note that <code>std::string_view</code> is <code>std::basic_string_view<char></code>.


===Filesystem===
===Filesystem===
Line 137: Line 174:
#include <iostream>
#include <iostream>
#include <fstream>
#include <fstream>
#include <string>


int main() {
int main() {
   std::istream my_file("my_file.txt");
   std::ifstream my_file("my_file.txt");
   std::string line;
   std::string line;
   // Read line by line
   // Read line by line
Line 153: 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>
#include <iostream>
#include <stdexcept>
#include <cstring> // for strerror


std::string get_file_contents(const std::string &filename)
std::string get_file_contents(std::string_view filename) {
{
   std::ifstream in(filename.data(), 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 170: Line 210:
   }
   }
   std::cerr << "Failed to open file: " << filename << std::endl;
   std::cerr << "Failed to open file: " << filename << std::endl;
   throw(errno);
   throw std::runtime_error(std::strerror(errno));
}
}
</syntaxhighlight>
</syntaxhighlight>
Line 178: Line 218:


[https://en.cppreference.com/w/cpp/regex Reference]
[https://en.cppreference.com/w/cpp/regex Reference]
<!--
<syntaxhighlight lang="C++>
#include <iostream>
#include <regex>
int main() {
  std::regex myRegex("(\\d+)");
  return 0;
}
</syntaxhighlight>
-->


===Thread===
===Thread===
Line 200: Line 228:
// Calling methods
// Calling methods
// You can also pass in parameters as usual
// You can also pass in parameters as usual
std::thread my_thread(&Class::method, this));
std::thread my_thread(&Class::method, this);
// Lambda functions
// Lambda functions
std::thread my_thread([&]() {
std::thread my_thread([&]() {
Line 218: Line 246:
<syntaxhighlight lang="C++">
<syntaxhighlight lang="C++">
std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1));
</syntaxhighlight >
</syntaxhighlight>
====Parallel For====
====Parallel For====
[https://www.alecjacobson.com/weblog/?p=4544 Reference]
[https://www.alecjacobson.com/weblog/?p=4544 Reference]
Line 228: Line 256:
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 254: Line 283:
;Notes
;Notes
* If the object you need is not very large, you can consider just including it as part of your class (or leaving it on the stack) rather than use pointers.
* If the object you need is not very large, you can consider just including it as part of your class (or leaving it on the stack) rather than use pointers.
* If you want to get a copy of the smart pointer to the current object, the object must '''publically''' inherit <code>std::enable_shared_from_this<T></code>
* If you want to get a copy of the smart pointer to the current object, the object must '''publicly''' inherit <code>std::enable_shared_from_this<T></code>
** Then you can call <code>shared_from_this()</code> from within any method (not the constructor).
** Then you can call <code>shared_from_this()</code> from within any method (not the constructor).
** 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 publicly 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 279: Line 309:


# Using free
# Using free
std::unique_ptr<void *, decltype(std::free) *> my_buffer(std::malloc(10), std::free);
std::unique_ptr<void, decltype(&std::free)> my_buffer(std::malloc(10), std::free);
</syntaxhighlight>
</syntaxhighlight>




====Deallocate====
====Deallocate====
Normally, containers such as <code>std::vector</code> will automatically deallocate memory from the heap when the destructor is called. However, occationally you may want to coerse this deallocation yourself.<br>
Normally, containers such as <code>std::vector</code> will automatically deallocate memory from the heap when the destructor is called. However, occasionally you may want to coerce this deallocation yourself.<br>
There are a few ways to do this:
There are a few ways to do this:
* Use smart pointers
* Use smart pointers
Line 297: Line 327:
// Swap
// Swap
std::vector<float> my_vector(99);
std::vector<float> my_vector(99);
my_vector = std::vector<float>;
my_vector = std::vector<float>();
// Or alternatively
// Or alternatively
// std::vector<float>().swap(my_vector);
// std::vector<float>().swap(my_vector);
// std::swap(my_vector, std::vector<float>);
// std::swap(my_vector, std::vector<float>());


// Swap for cl::Buffer
// Swap for cl::Buffer
Line 341: Line 371:
#include <iostream>
#include <iostream>
#include <algorithm>
#include <algorithm>
#include <vector>


int main()
int main()
Line 346: Line 377:
     std::random_device rd;
     std::random_device rd;
     std::mt19937 gen(rd());
     std::mt19937 gen(rd());
     # Fill with integers in [0, 10]
     // Fill with integers in [0, 10]
     std::uniform_int_distribution<> dis(0, 10);
     std::uniform_int_distribution<> dis(0, 10);


     std::vector<int> my_vec(10, 0);
     std::vector<int> my_vec(10, 0);
     std::generate(my_vec.begin(), my_vec.end(), [&](){return dis(gen);});
     std::generate(my_vec.begin(), my_vec.end(), [&](){return dis(gen);});
   
   
     for (int v : my_vec) {
     for (int v : my_vec) {
         std::cout << v << " ";
         std::cout << v << " ";
Line 362: Line 393:


===Numeric===
===Numeric===
<code>#include <numeric></code>
====std::iota====
====std::iota====
[https://en.cppreference.com/w/cpp/algorithm/iota Reference]<br>
[https://en.cppreference.com/w/cpp/algorithm/iota Reference]<br>
Line 381: Line 413:
===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 387: Line 421:
auto end = std::chrono::high_resolution_clock::now();
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Time elapsed: "  
std::cout << "Time elapsed: "  
           << std::chrono::duration_case<std::chrono::milliseconds>(end - start).count()  
           << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()  
           << " ms" << std::endl;
           << " ms" << std::endl;
</syntaxhighlight>
</syntaxhighlight>
Line 393: Line 427:
===Execution===
===Execution===
<code>#include <execution></code><br>
<code>#include <execution></code><br>
The execution header gives you tools for parallel execution.<br>
The execution header gives you tools for parallel execution (since C++17).<br>
See [https://en.cppreference.com/w/cpp/algorithm/execution_policy_tag_t execution_policy_tag].<br>
See [https://en.cppreference.com/w/cpp/algorithm/execution_policy_tag_t execution_policy_tag].<br>
[https://devblogs.microsoft.com/cppblog/using-c17-parallel-algorithms-for-better-performance/ C++17 Parallel Algorithms blog].<br>
[https://devblogs.microsoft.com/cppblog/using-c17-parallel-algorithms-for-better-performance/ C++17 Parallel Algorithms blog].<br>
[https://developer.nvidia.com/blog/accelerating-standard-c-with-gpus-using-stdpar/ Nvidia Accelerating Standard C++ with GPUs Using stdpar]<br>
;Parallel Sorting Example
;Parallel Sorting Example
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
std::sort(std::execution::par_unseq, sorted.begin(), sorted.end());
std::sort(std::execution::par_unseq, sorted.begin(), sorted.end());
</syntaxhighlight>
</syntaxhighlight>
* <code>std::execution::seq</code> sequential
* <code>std::execution::unseq</code> vectorized only (C++20)
* <code>std::execution::par</code> parallel
* <code>std::execution::par_unseq</code> parallel and vectorized


===Random===
===Random===
Line 415: Line 456:
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==
STL is the Standard Template Library originally implemented in 1994 by Stepanov and Lee from HP.
STL is the Standard Template Library originally implemented in 1994 by Stepanov and Lee from HP.<br>
STL consists of a general set of algorithms, containers, functions, and iterators, many of which are now built into the standard library (std) of C++
STL consists of a general set of algorithms, containers, functions, and iterators.<br>
This section focuses only on the portions of STL which have been incorporated into the C++ standard library.
Today, STL refers to those containers and algorithms which are now built into the standard library (std) of C++.


===Simple Containers===
===Simple Containers===
====std::pair====
====std::pair====
[https://en.cppreference.com/w/cpp/utility/pair std::pair]


===Sequences===
===Sequences===
====std::array====
====std::array====
<code>#include <array></code><br>
<code>#include <array></code><br>
In C++, you can use <code>std::vector</code> which gives you a resizable array.
This wrapper around C-style arrays gives us size information and allows the array to be passed around by reference while keeping the array on the stack or in a struct.
This will allocate an array in the heap.<br>
Unless you need stack allocation or allocation into a struct, you should probably use a vector.
 
[https://shendrick.net/Coding%20Tips/2015/03/15/cpparrayvsvector.html array vs vector]<br>
If you need a statically allocated array, you can use <code>std::array</code> in the <code>array</code> header.<br>
This wrapper around C-style arrays gives us size information and allows the array to be passed around by reference while keeping the array on the stack unlike <code>std::vector</code>.<br>
If you want to manually allocate an array on the heap, you can do so as follows:
<syntaxhighlight lang="C++">
auto my_arr = std::make_shared<std::array<char,64>>();
</syntaxhighlight>


====std::vector====
====std::vector====
[https://en.cppreference.com/w/cpp/container/vector Reference]<br>
<code>#include <vector></code>
Use vector for almost everything...<br>
https://en.cppreference.com/w/cpp/container/vector<br>
It is an ArrayList.<br>
This is a dynamically-allocated resizable array, known as an ArrayList in Java.<br>
Note that <code>vector<bool></code> is not an array of bools.<br>
This has several nuances so you should use <code>vector<char></code> instead.<br>
<syntaxhighlight lang="c++">
<syntaxhighlight lang="c++">
// Basics
// Basics
vector my_vec;
std::vector<int> my_vec;
// Vector with size 5
// Vector with size 5
vector my_vec(5);
std::vector<int> my_vec(5);
// Vector with size 5 initialized to 1
// Vector with size 5 initialized to 1
vector my_vec(5, 1);
std::vector<int> my_vec(5, 1);


// Length of vector
// Length of vector
Line 466: Line 509:
my_vec.back();
my_vec.back();
</syntaxhighlight>
</syntaxhighlight>
Note that [https://en.cppreference.com/w/cpp/container/vector_bool <code>vector<bool></code>] is a special case of bit-packed booleans instead of an array of bools. You should use <code>vector<char></code> instead if your code relies on it being contiguous.<br>
====std::span====
<code>#include <span&gt;</code><br>
https://en.cppreference.com/w/cpp/container/span<br>
This is view of some contiguous amount of memory. If the size is static, this is equivalent to a single pointer, otherwise is it equivalent to two pointers (i.e. begin and end).
If you use this as the parameter to your function, it will accept both arrays and vectors.
Additionaly, there is a [https://en.cppreference.com/w/cpp/container/span/subspan subspan] function so you don't need to pass around indices or pointers to get subvectors.


====std::deque====
====std::deque====
Line 471: Line 523:


====std::list====
====std::list====
This is a doubly linked list. You can delete elements from the middle of the list if you know have an iterator.
This is a doubly linked list. You can delete elements from the middle of the list if you have an iterator.
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
list<int> m_list;
std::list<int> m_list;


list<int>::iterator m_it = m_list.insert(5);
// Insert requires an iterator position
std::list<int>::iterator m_it = m_list.insert(m_list.begin(), 5);


// Remove the element
// Remove the element
Line 485: Line 538:
[https://en.cppreference.com/w/cpp/container/queue Reference]<br>
[https://en.cppreference.com/w/cpp/container/queue Reference]<br>
<syntaxhighlight lang="c++">
<syntaxhighlight lang="c++">
std::queue<int> my_queue;


my_queue.push(a);
auto val = my_queue.front();
my_queue.pop(); // returns void
</syntaxhighlight>
</syntaxhighlight>


Line 500: Line 557:
// Peek
// Peek
// Always make sure stack is not empty
// Always make sure stack is not empty
char top = my_stack.top('a');
char top = my_stack.top();


// Pop
// Pop
Line 507: Line 564:
my_stack.pop();
my_stack.pop();
</syntaxhighlight>
</syntaxhighlight>
====std::priority_queue====
This is a min/max heap.


===Associative Containers===
===Associative Containers===
Also known as maps or associative arrays.
Also known as maps or associative arrays.
====std::set====
[https://en.cppreference.com/w/cpp/container/set reference]<br>
<code>#include<set></code><br>
This is a binary tree (likely red-black tree). You can assume <math>O(\log n)</math> operations.
====std::map====
[https://en.cppreference.com/w/cpp/container/map reference]<br>
<code>#include<map></code><br>
This is a binary tree (likely red-black tree). You can assume <math>O(\log n)</math> operations.
====std::unordered_set====
====std::unordered_set====
[https://en.cppreference.com/w/cpp/container/unordered_set reference]<br>
<code>#include <unordered_set></code><br>
<code>#include <unordered_set></code><br>
This is a hashset.<br>
This is a hashset. You can assume operations are <math>O(1)</math> on average and <math>O(N)</math> worst case.<br>
<syntaxhighlight lang="cpp>
<syntaxhighlight lang="cpp">
std::unordered_set<int> my_set;
std::unordered_set<int> my_set;
// add things to myset
// Add
my_set.insert(5);
my_set.insert(5);
// Check contains
// Check contains
my_set.find(5) != my_set.end();
my_set.find(5) != my_set.end(); // Before C++20
my_set.contains(5); // C++20
// Remove
my_set.erase(5);
</syntaxhighlight>
</syntaxhighlight>
====std::unordered_map====
====std::unordered_map====
[https://en.cppreference.com/w/cpp/container/unordered_map reference]<br>
<code>#include<unordered_map></code><br>
This is a hashmap. You can assume operations are <math>O(1)</math> on average and <math>O(N)</math> worst case.<br>
<syntaxhighlight lang="C++">
std::unordered_map<int, std::string> my_map;
my_map[5] = "hey"; // Fine as long as value type is default-constructible
my_map.insert({5, "hey"});
my_map.find(5) != my_map.end();
my_map.contains(5); // C++20
</syntaxhighlight>
;Custom Keys
;Custom Keys
How to use a rational number as a key in C++
How to use a rational number as a key in C++
Line 537: Line 623:
</syntaxhighlight>
</syntaxhighlight>


==Boost==
==Functional Programming==
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>. Paired with [https://adaptivecpp.github.io/AdaptiveCpp/stdpar/ AdaptiveCPP], some operations can be automatically GPU accelerated as well.
Most of these require C++20.
===Map===
* <code>std::for_each</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===
* <code>std::reduce</code>
* <code>std::accumulate</code>
* [https://en.cppreference.com/w/cpp/algorithm/ranges/fold_left <code>std::ranges::fold_left</code>] (C++23)
===Filter===
* <code>std::copy_if</code>
* <code>std::remove_if</code>
* <code>std::find_if</code>


==Programming Styles==
==Programming Styles==
Line 544: Line 650:
[https://github.com/rigtorp/awesome-modern-cpp List of resources]<br>
[https://github.com/rigtorp/awesome-modern-cpp List of resources]<br>
* Use RAII principles.
* Use RAII principles.
* Use smart pointers instead of new and delete.
** I.e. each object should manage its own memory rather than the caller having to manage it.
** Namely, <code>std::make_unique</code> and <code>std::shared_ptr</code>.
** You should never use `malloc` and `free` unless interfacing with C libraries.
** Or <code>std::vector<char></code> if you just need some memory in the heap.
* Avoid the use of new and delete, instead using vector or smart pointers.
* Use clang-format.
* Use clang-format.


Line 552: Line 658:
* [https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md CppCoreGuidelines]
* [https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md CppCoreGuidelines]
* [https://google.github.io/styleguide/cppguide.html Google C++ Style Guide] - note that some people dislike this since it is focused on interoperability and suggests avoiding exceptions.
* [https://google.github.io/styleguide/cppguide.html Google C++ Style Guide] - note that some people dislike this since it is focused on interoperability and suggests avoiding exceptions.
===Orthodox C++===
[https://gist.github.com/bkaradzic/2e39896bc7d8c34e042b Reference]<br>
Somewhat opposite of modern C++.<br>
Also known as "C with Classes"<br>
Basically only use C++ for its classes. Do everything else C-style.<br>
The main benefit is compatibility with older compilers/libraries and easier understanding for people less familiar with newer C++ features.
* Don't use C++ runtime wrapper for C runtime includes (<cstdio>, <cmath>, etc.), use C runtime instead (<stdio.h>, <math.h>, etc.)
* Don't use stream (<iostream>, <stringstream>, etc.), use printf style functions instead.
* Don't use anything from STL that allocates memory, unless you don't care about memory management.
* Don't use exceptions.
* Don't use RTTI.


==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 (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 595: Line 705:
     dumb_array(const dumb_array& other)
     dumb_array(const dumb_array& other)
         : mSize(other.mSize),
         : mSize(other.mSize),
           mArray(mSize ? new int[mSize] : nullptr),
           mArray(mSize ? new int[mSize] : nullptr)
     {
     {
         // note that this is non-throwing, because of the data
         // note that this is non-throwing, because of the data
Line 609: Line 719:
     }
     }


    // 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 618: Line 737:
         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 642: Line 748:
==Useful Libraries==
==Useful Libraries==
A list of useful libraries
A list of useful libraries
===Boost===
{{main | Boost (C++ libraries)}}
A set of popular C++ libraries. Most are header-only.
===cxxopts===
===cxxopts===
[https://github.com/jarro2783/cxxopts Link]<br>
[https://github.com/jarro2783/cxxopts Link]<br>
Line 649: Line 760:
{{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]]