C++: Difference between revisions

From David's Wiki
No edit summary
(43 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>
Some people may think of it as an object-oriented version of C.


==Usage==
==Usage==
How to do things using the [https://en.wikipedia.org/wiki/C%2B%2B_Standard_Library C++ standard library (stdlib)].
How to do things using the [https://en.wikipedia.org/wiki/C%2B%2B_Standard_Library C++ standard library (stdlib)].
===Compilation===
===Compilation===
{{See also|CMake|Makefile}}
====g++====
====g++====
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Line 11: Line 14:
* <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 optmizations
===Strings===
 
===Syntax===
====Main====
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>.
These can be easily converted to a <code>std::vector<std::string></code> for convenience.
<syntaxhighlight lang="cpp">
#include <string>
#include <vector>
int main(int argc, char *argv[]) {
  std::vector<std::string> args(argv, argv + argc);
  // Your code here
  return EXIT_SUCCESS;
}
</syntaxhighlight>
 
====Headers====
[https://stackoverflow.com/questions/10694255/cmath-vs-math-h-and-similar-c-prefixed-vs-h-extension-headers Reference]
C++ includes C-headers such as <code>math.h</code> and <code>cmath</code>.<br>
The C-style header will place everything in the global namespace while the C++ header will place everything in <code>std</code>.<br>
You should use <code>cmath</code>.
 
====Lambda Expressions====
[https://en.cppreference.com/w/cpp/language/lambda Reference]
 
====Casting====
[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.
These are the main ones you should use.
* <code>static_cast</code>
* <code>dynamic_cast</code>
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>.
 
===Array===
<code>#include <array></code><br>
In C++, you can use <code>std::vector</code> which gives you a resizable array.
This will allocate an array in the heap.<br>
 
[https://shendrick.net/Coding%20Tips/2015/03/15/cpparrayvsvector.html array vs vector]<br>
If you need a static sized 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 allocate a static array on the heap, you can do so as follows:
<syntaxhighlight lang="C++">
auto my_arr = std::make_shared<std::array<char,64>>();
</syntaxhighlight>
 
===String===
<code>#include <string></code><br>
====String Interpolation====
====String Interpolation====
[https://stackoverflow.com/questions/10410023/string-format-alternative-in-c Reference]
[https://stackoverflow.com/questions/10410023/string-format-alternative-in-c Reference]
Line 30: Line 80:
</syntaxhighlight>
</syntaxhighlight>
===Filesystem===
===Filesystem===
<code>#include <fstream></code><br>
====Reading and Writing====
====Reading and Writing====
Reading and writing is done using <code>fstream</code>.<br>
Reading and writing is done using <code>fstream</code>.<br>
Line 46: Line 97:
   }
   }
   return 0;
   return 0;
}
</syntaxhighlight>
====Reading a whole file====
[https://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html Reference and comparison of different methods]
<syntaxhighlight lang="C++">
#include <fstream>
#include <string>
#include <cerrno>
std::string get_file_contents(std::string filename)
{
  std::ifstream in(filename, std::ios::in | std::ios::binary);
  if (in)
  {
    std::string contents;
    in.seekg(0, std::ios::end);
    contents.resize(in.tellg());
    in.seekg(0, std::ios::beg);
    in.read(&contents[0], contents.size());
    return contents;
  }
  throw(errno);
}
}
</syntaxhighlight>
</syntaxhighlight>


===Regular Expressions===
===Regular Expressions===
<code>#include <regex></code><br>
[https://en.cppreference.com/w/cpp/regex Reference]
[https://en.cppreference.com/w/cpp/regex Reference]
<!--
<!--
Line 63: Line 138:
-->
-->


===Threading===
===Thread===
<code>#include <thread></code><br>
==== Sleep ====
==== Sleep ====
<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====
[https://www.alecjacobson.com/weblog/?p=4544 Reference]


===Memory===
===Memory===
<code>#include <memory></code><br>
====Smart Pointers====
====Smart Pointers====
[https://www.geeksforgeeks.org/auto_ptr-unique_ptr-shared_ptr-weak_ptr-2/ Smart Pointers]<br>
[https://www.geeksforgeeks.org/auto_ptr-unique_ptr-shared_ptr-weak_ptr-2/ Smart Pointers]<br>
There are 4 types of smart pointers
Smart pointers were added in C++11.<br>
There are 4 types of smart pointers:
* <code>auto_ptr</code> which is [https://stackoverflow.com/questions/3697686/why-is-auto-ptr-being-deprecated deprecated]
* <code>auto_ptr</code> which is [https://stackoverflow.com/questions/3697686/why-is-auto-ptr-being-deprecated deprecated]
* <code>unique_ptr</code>
* <code>unique_ptr</code>
Line 80: Line 160:
Use <code>shared_ptr</code> when multiple objects need to reference the same thing.<br>
Use <code>shared_ptr</code> when multiple objects need to reference the same thing.<br>
Use <code>weak_ptr</code> to avoid cyclic dependencies which cause issues with reference counting.<br>
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>
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.
Example:
<syntaxhighlight lang="cpp">
// Block-scope car
Car my_car;
// Old C++
// Must call delete my_car; to avoid memory leaks.
Car *my_car = new Car();
// Using unique ptr
std::unique_ptr<Car> my_car(new Car());
// Or starting from C++14
auto my_car = std::make_unique<Car>();
</syntaxhighlight>
Note: 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.


====Garbage Collection====
====Garbage Collection====
Starting from C++14, you should use smart pointers such as [https://en.cppreference.com/w/cpp/memory/shared_ptr <code>shared_ptr</code>] which have automatic garbage collection.<br>
Starting from C++11, you should use smart pointers such as [https://en.cppreference.com/w/cpp/memory/shared_ptr <code>shared_ptr</code>] which have automatic garbage collection.<br>
<br>
<br>
Traditional C++ does not have garbage collection.<br>
Traditional C++ does not have garbage collection.<br>
Line 88: Line 186:
You can also use C allocation with <code>malloc</code>, <code>calloc</code>, <code>alloca</code>, and <code>free</code>, though it is [https://stackoverflow.com/questions/184537/in-what-cases-do-i-use-malloc-and-or-new not recommended] since these are not type-safe.<br>
You can also use C allocation with <code>malloc</code>, <code>calloc</code>, <code>alloca</code>, and <code>free</code>, though it is [https://stackoverflow.com/questions/184537/in-what-cases-do-i-use-malloc-and-or-new not recommended] since these are not type-safe.<br>


===Casting===
====Custom Deleter====
[https://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used Types of casts]
[https://www.bfilipek.com/2016/04/custom-deleters-for-c-smart-pointers.html Custom Deleters]<br>
C++ has several types of casts.
When using smart pointers, the default deleter is the <code>delete</code> function but you can also specify your own deleter.
These are the main ones.
 
* <code>const_cast</code>
 
* <code>static_cast</code>
<syntaxhighlight lang="cpp">
* <code>dynamic_cast</code>
# Using a functor
struct AVFrameDeleter {
  void operator()(AVFrame *p) { av_frame_free(&p); }
};
std::unique_ptr<AVFrame, AVFrameDeleter> rgb_frame(av_frame_alloc());
 
# Using free
std::unique_ptr<void *, decltype(std::free) *> my_buffer(std::malloc(10), std::free);
</syntaxhighlight>
 
 
====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>
There are a few ways to do this:
* Use smart pointers
* Swap
* Call a clear/shrink/deallocate function
Example [https://stackoverflow.com/questions/3054567/right-way-to-deallocate-an-stdvector-object Reference]:
<syntaxhighlight lang="cpp">
// Using smart pointers
std::unique_ptr<std::vector<float>> my_vector = make_unique<std::vector<float>>(99);
my_vector.reset();
 
// Swap
std::vector<float> my_vector(99);
my_vector = std::vector<float>;
// Or alternatively
// std::vector<float>().swap(my_vector);
 
// Swap for cl::Buffer
cl::Buffer my_buf(context, CL_MEM_READ_WRITE, size);
my_buf = cl::Buffer();
 
// Clear and shrink
// Specific to std::vector
std::vector<float> my_vector(99);
my_vector.clear();
my_vector.shrink_to_fit();
 
</syntaxhighlight>
 
===Limits===
<code>#include <limits></code><br>
[https://en.cppreference.com/w/cpp/types/numeric_limits Reference]<br>
C++ has standard macros such as <code>INT_MAX</code>.<br>
The limits header adds these limits for every type.<br>
<syntaxhighlight lang="cpp">
// Equivalent to FLT_MAX
std::numeric_limits<float>::max();
</syntaxhighlight>
 
==STL==
STL is the Standard Template Library.<br>
STL can either refer to the 1994 original STL implementation by Stepanov and Lee from HP or the general set of algorithms, containers, functions, and iterators.<br>
Many STL containers are now built into the standard library (std) of C++.<br>
This section focuses only on the portions of STL which have been incorporated into the C++ standard library.
 
===Simple Containers===
====std::pair====
 
===Sequences===
====std::vector====
====std::list====
 
===Container adaptors===
====std::queue====
====std::stack====
 
===Associative Containers===
Also known as maps or associative arrays.
====std::unordered_set====
<code>#include <unordered_set></code><br>
This is a hashset.<br>
<syntaxhighlight lang="cpp>
std::unordered_set<int> my_set;
// add things to myset
my_set.insert(5);
// Check contains
my_set.find(5) != my_set.end();
</syntaxhighlight>
====std::unordered_map====
 
==Boost==
 


==Programming Styles==
==Programming Styles==
Line 105: Line 286:
[https://gist.github.com/bkaradzic/2e39896bc7d8c34e042b Reference]<br>
[https://gist.github.com/bkaradzic/2e39896bc7d8c34e042b Reference]<br>
Somewhat opposite of modern C++.<br>
Somewhat opposite of modern C++.<br>
Basically only use C++ for its classes. Do everything else C-style.  
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.
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 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 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 anything from STL that allocates memory, unless you don't care about memory management.
* Don't use exceptions.
* Don't use RTTI.


==Boost==
==Useful Libraries==
==STL==
A list of useful libraries
===cxxopts===
[https://github.com/jarro2783/cxxopts Link]<br>
A header-only C++ argument parser.<br>
Note that if you already use Boost, you can use <code>Boost::Program_options</code> instead.
===Eigen===
{{main | Eigen (C++ library)}}
A C++ linear algebra library.

Revision as of 03:00, 26 November 2019

C++ is a very popular and powerful language which includes all the low-level features of C (e.g. pointers, operator overloading) along many high-level features (regex, STL containers) thanks to the C++ standard library.
Some people may think of it as an object-oriented version of C.

Usage

How to do things using the C++ standard library (stdlib).

Compilation

g++

g++ my_driver.c [-Iincludefolder] -o my_program.out

Misc optimizations

  • -std=c++17 for C++17 support
  • -O3 for level 3 optmizations

Syntax

Main

All C++ programs launch in a main function. Similar to C, the arguments are int argc and char *argv[]. These can be easily converted to a std::vector<std::string> for convenience.

#include <string>
#include <vector>
int main(int argc, char *argv[]) {
  std::vector<std::string> args(argv, argv + argc);
  // Your code here
  return EXIT_SUCCESS;
}

Headers

Reference C++ includes C-headers such as math.h and cmath.
The C-style header will place everything in the global namespace while the C++ header will place everything in std.
You should use cmath.

Lambda Expressions

Reference

Casting

Types of casts C++ has several types of casts. These are the main ones you should use.

  • static_cast
  • dynamic_cast

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 reinterpret_cast.

Array

#include <array>
In C++, you can use std::vector which gives you a resizable array. This will allocate an array in the heap.

array vs vector
If you need a static sized array, you can use std::array in the array header.
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 std::vector.
If you want to allocate a static array on the heap, you can do so as follows:

auto my_arr = std::make_shared<std::array<char,64>>();

String

#include <string>

String Interpolation

Reference

#include <iostream>
#include <sstream>
#include <string>

int main() {
    std::string a = "a", b = "b", c = "c";
    // apply formatting
    std::stringstream s;
    s << a << " " << b << " > " << c;
    // assign to std::string
    std::string str = s.str();
    std::cout << str << "\n";
}

Filesystem

#include <fstream>

Reading and Writing

Reading and writing is done using fstream.
If you don't need r/w, use istream for reading or ostream for writing.

#include <iostream>
#include <fstream>

int main() {
  std::istream my_file("my_file.txt");
  std::string line;
  # Read line by line
  # You can also read using <<
  while (getline(my_file, line)) {
    std::cout << line << std::endl;
  }
  return 0;
}

Reading a whole file

Reference and comparison of different methods

#include <fstream>
#include <string>
#include <cerrno>

std::string get_file_contents(std::string filename)
{
  std::ifstream in(filename, std::ios::in | std::ios::binary);
  if (in)
  {
    std::string contents;
    in.seekg(0, std::ios::end);
    contents.resize(in.tellg());
    in.seekg(0, std::ios::beg);
    in.read(&contents[0], contents.size());
    return contents;
  }
  throw(errno);
}

Regular Expressions

#include <regex>
Reference

Thread

#include <thread>

Sleep

std::this_thread::sleep_for(std::chrono::milliseconds(1));

Parallel For

Reference

Memory

#include <memory>

Smart Pointers

Smart Pointers
Smart pointers were added in C++11.
There are 4 types of smart pointers:

  • auto_ptr which is deprecated
  • unique_ptr
  • shared_ptr
  • weak_ptr

Use unique_ptr for ownership models.
Use shared_ptr when multiple objects need to reference the same thing.
Use weak_ptr to avoid cyclic dependencies which cause issues with reference counting.
If you are using C++14 or newer, you should use make_unique or make_shared which will only make one memory allocation for both the object and the pointer rather than two memory allocations.
Alternatively if you already have a smart pointer, you can call my_ptr.reset(new Car()) to change the pointer or my_ptr.reset() to deallocate the object referenced by the pointer. Example:

// Block-scope car
Car my_car;

// Old C++
// Must call delete my_car; to avoid memory leaks.
Car *my_car = new Car();

// Using unique ptr
std::unique_ptr<Car> my_car(new Car());

// Or starting from C++14
auto my_car = std::make_unique<Car>();

Note: 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.

Garbage Collection

Starting from C++11, you should use smart pointers such as shared_ptr which have automatic garbage collection.

Traditional C++ does not have garbage collection.
After using new to allocate an object, use delete to deallocate it.
You can also use C allocation with malloc, calloc, alloca, and free, though it is not recommended since these are not type-safe.

Custom Deleter

Custom Deleters
When using smart pointers, the default deleter is the delete function but you can also specify your own deleter.


# Using a functor
struct AVFrameDeleter {
  void operator()(AVFrame *p) { av_frame_free(&p); }
};
std::unique_ptr<AVFrame, AVFrameDeleter> rgb_frame(av_frame_alloc());

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


Deallocate

Normally, containers such as std::vector will automatically deallocate memory from the heap when the destructor is called. However, occationally you may want to coerse this deallocation yourself.
There are a few ways to do this:

  • Use smart pointers
  • Swap
  • Call a clear/shrink/deallocate function

Example Reference:

// Using smart pointers
std::unique_ptr<std::vector<float>> my_vector = make_unique<std::vector<float>>(99);
my_vector.reset();

// Swap
std::vector<float> my_vector(99);
my_vector = std::vector<float>;
// Or alternatively
// std::vector<float>().swap(my_vector);

// Swap for cl::Buffer
cl::Buffer my_buf(context, CL_MEM_READ_WRITE, size);
my_buf = cl::Buffer();

// Clear and shrink
// Specific to std::vector
std::vector<float> my_vector(99);
my_vector.clear();
my_vector.shrink_to_fit();

Limits

#include <limits>
Reference
C++ has standard macros such as INT_MAX.
The limits header adds these limits for every type.

// Equivalent to FLT_MAX
std::numeric_limits<float>::max();

STL

STL is the Standard Template Library.
STL can either refer to the 1994 original STL implementation by Stepanov and Lee from HP or the general set of algorithms, containers, functions, and iterators.
Many STL containers are now built into the standard library (std) of C++.
This section focuses only on the portions of STL which have been incorporated into the C++ standard library.

Simple Containers

std::pair

Sequences

std::vector

std::list

Container adaptors

std::queue

std::stack

Associative Containers

Also known as maps or associative arrays.

std::unordered_set

#include <unordered_set>
This is a hashset.

std::unordered_set<int> my_set;
// add things to myset
my_set.insert(5);
// Check contains
my_set.find(5) != my_set.end();

std::unordered_map

Boost

Programming Styles

Modern C++

List of resources
Prefer newer std functions available in C++17.
Use shared pointers instead of new and delete.

  • Use clang-format.

Orthodox C++

Reference
Somewhat opposite of modern C++.
Also known as "C with Classes"
Basically only use C++ for its classes. Do everything else C-style.
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.

Useful Libraries

A list of useful libraries

cxxopts

Link
A header-only C++ argument parser.
Note that if you already use Boost, you can use Boost::Program_options instead.

Eigen

A C++ linear algebra library.