C++: Difference between revisions
No edit summary |
|||
| (11 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 (RAII, STD algorithms, STL containers) thanks to the C++ standard library. | 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. | ||
==Usage== | ==Usage== | ||
| Line 10: | Line 10: | ||
====g++==== | ====g++==== | ||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
g++ my_driver. | g++ my_driver.cpp [-Iincludefolder] -o my_program.out | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Standard optimizations | Standard optimizations | ||
| Line 54: | Line 54: | ||
====References==== | ====References==== | ||
References are accepted or | References are accepted or stored using <code>&</code>.<br> | ||
For example: | For example: | ||
<syntaxhighlight lang="c++"> | <syntaxhighlight lang="c++"> | ||
| Line 68: | Line 68: | ||
====Types==== | ====Types==== | ||
For simple programs, you can use the standard types: | For simple programs, you can use the standard types: | ||
* <code>int</code>, <code> | * <code>int</code>, <code>unsigned int</code>, <code>long</code>, <code>size_t</code> | ||
* <code>float</code>, <code>double</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. | 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> | 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> | [https://en.cppreference.com/w/cpp/header/cstdint cppreference cstdint]<br> | ||
I recommend using these for anything with specific or high precision requirements.<br> | I recommend using these for anything with specific or high precision requirements.<br> | ||
| 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"> | ||
// 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 93: | 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 114: | Line 115: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==== | ====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> | ||
| Line 173: | Line 174: | ||
#include <iostream> | #include <iostream> | ||
#include <fstream> | #include <fstream> | ||
#include <string> | |||
int main() { | int main() { | ||
| 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 < | #include <string_view> | ||
#include <iostream> | |||
#include <stdexcept> | |||
#include <cstring> // for strerror | |||
std::string get_file_contents( | 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 206: | 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 214: | Line 218: | ||
[https://en.cppreference.com/w/cpp/regex Reference] | [https://en.cppreference.com/w/cpp/regex Reference] | ||
===Thread=== | ===Thread=== | ||
| Line 236: | 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 254: | 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 264: | 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: | ||
* | * [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>std::shared_ptr</code> - the memory has multiple owners. | |||
* <code>std::weak_ptr</code> - a non-owning reference to a shared_ptr. | |||
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. | |||
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> | |||
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 290: | 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 ''' | * 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 | ** 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. | * <code>std::auto_ptr</code> was a predecessor to <code>std::unique_ptr</code> which allowed copies. It shouldn't be used anymore. | ||
| Line 316: | Line 309: | ||
# Using free | # Using free | ||
std::unique_ptr<void | 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, | 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 334: | 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 378: | Line 371: | ||
#include <iostream> | #include <iostream> | ||
#include <algorithm> | #include <algorithm> | ||
#include <vector> | |||
int main() | int main() | ||
| Line 383: | Line 377: | ||
std::random_device rd; | std::random_device rd; | ||
std::mt19937 gen(rd()); | std::mt19937 gen(rd()); | ||
// 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 399: | 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 418: | Line 413: | ||
===Chrono=== | ===Chrono=== | ||
<code>#include <chrono></code><br> | <code>#include <chrono></code><br> | ||
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 459: | Line 456: | ||
std::cout << '\n'; | std::cout << '\n'; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
===const=== | ===const=== | ||
| Line 485: | Line 481: | ||
<code>#include <array></code><br> | <code>#include <array></code><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 or in a struct. | 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. | ||
Unless you need stack allocation or allocation into a struct, you | Unless you need stack allocation or allocation into a struct, you should probably use a vector. | ||
====std::vector==== | ====std::vector==== | ||
| Line 493: | Line 489: | ||
<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 514: | Line 510: | ||
</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 | 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==== | ====std::span==== | ||
<code>#include | <code>#include <span></code><br> | ||
https://en.cppreference.com/w/cpp/container/span<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). | 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). | ||
| Line 527: | Line 523: | ||
====std::list==== | ====std::list==== | ||
This is a doubly linked list. You can delete elements from the middle of the list if you | 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 560: | Line 557: | ||
// Peek | // Peek | ||
// Always make sure stack is not empty | // Always make sure stack is not empty | ||
char top = my_stack.top( | char top = my_stack.top(); | ||
// Pop | // Pop | ||
| Line 588: | Line 585: | ||
<code>#include <unordered_set></code><br> | <code>#include <unordered_set></code><br> | ||
This is a hashset. You can assume operations are <math>O(1)</math> on average and <math>O(N)</math> worst case.<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 | // Add | ||
| Line 605: | Line 602: | ||
<syntaxhighlight lang="C++"> | <syntaxhighlight lang="C++"> | ||
std::unordered_map<int, std::string> my_map; | std::unordered_map<int, std::string> my_map; | ||
my_map[5] = "hey"; // Fine as long as value type is | my_map[5] = "hey"; // Fine as long as value type is default-constructible | ||
my_map.insert({5, "hey"}); | my_map.insert({5, "hey"}); | ||
my_map.find(5) != my_map.end(); | my_map.find(5) != my_map.end(); | ||
my_map.contains(5); // C++20 | my_map.contains(5); // C++20 | ||
| Line 653: | 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. | ||
** I.e. each object should manage | ** I.e. each object should manage its 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. | ||
* Avoid the use of new and delete, instead using vector or smart pointers. | * Avoid the use of new and delete, instead using vector or smart pointers. | ||
| Line 708: | 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 766: | Line 763: | ||
===absl=== | ===absl=== | ||
https://github.com/abseil/abseil-cpp is a library used by Google which supplements the standard library. | 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]] | ||