C++: Difference between revisions

No edit summary
No edit summary
 
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.cc [-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.
Line 85: Line 85:


<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 95: 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 116: 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 175: Line 174:
#include <iostream>
#include <iostream>
#include <fstream>
#include <fstream>
#include <string>


int main() {
int main() {
Line 195: Line 195:
#include <string>
#include <string>
#include <string_view>
#include <string_view>
#include <iostream>
#include <stdexcept>
#include <cstring> // for strerror


std::string get_file_contents(std::string_view filename) {
std::string get_file_contents(std::string_view filename) {
   std::ifstream in(filename, std::ios::in | std::ios::binary);
   std::ifstream in(filename.data(), std::ios::in | std::ios::binary);
   if (in.good()) {
   if (in.good()) {
     std::string contents;
     std::string contents;
Line 207: 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 215: 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 255: 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 292: 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 318: 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 339: Line 330:
// 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 380: Line 371:
#include <iostream>
#include <iostream>
#include <algorithm>
#include <algorithm>
#include <vector>


int main()
int main()
Line 385: 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 401: 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 488: 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 496: 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 517: 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 530: 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 591: 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 608: 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 656: 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.