C++: Difference between revisions

No edit summary
 
(10 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.c [-Iincludefolder] -o my_program.out
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 store using <code>&</code>.<br>
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>uint</code>, <code>long</code>, <code>size_t</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>


====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>
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 <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 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]
<!--
<syntaxhighlight lang="C++>
#include <iostream>
#include <regex>
int main() {
  std::regex myRegex("(\\d+)");
  return 0;
}
</syntaxhighlight>
-->


===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:
* <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 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 '''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.
* <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 *, 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 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]
     // 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>
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 484: 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 are should probably use a vector.
Unless you need stack allocation or allocation into a struct, you should probably use a vector.


====std::vector====
====std::vector====
Line 492: 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 513: 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 continguous.<br>
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 &lt;span&gt;</code><br>
<code>#include <span&gt;</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 526: 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 559: 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 587: 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 604: 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 not a reference.
my_map[5] = "hey"; // Fine as long as value type is default-constructible
my_map.insert({5, "hey"}); // Necessary if value type is a reference.
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 652: 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 it's own memory rather than the caller having to manage it.
** 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 707: 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 765: 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]]