- Don't WTF quite so much when looking at C++ PRs
- Know what you don't know (so you know what to look up to learn more)
- Some new stuff
- Some language oddities
- Some OO specifics
- Templating
- Compilers, CMake, and you
- Where to learn more?
- Random topics as time allows
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
There can only be one main
.
$ ls
main.cc
$ cat main.cc
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
$ clang++ ./main.cc
$ ./a.out
Hello, World!
- Some new stuff
- Some language oddities
- Some OO specifics
- Templating
- Compilers, CMake, and you
- Where to learn more?
- Random topics as time allows
C++14 and C++17: Not your father's C++
- More
auto
using
(templates for typedefs)- Lambdas
- Range-based
for
- Smart(er) pointers
- std::move and rvalue-refs
- threading API
For types:
auto numbers = std::vector<int> {1,2,3};
For return values:
auto next(int i) {
return i + 1;
}
Later: Force the compiler to tell us what the auto
is deduced to.
auto printer = [](auto c) {
std::cout << c << std::endl;
};
printer("Foo");
The []
lets you capture outside variables.
auto numbers = std::vector<int> {1,2,3};
for(auto number : numbers) {
std::cout << number << std::endl;
}
No more new
:
auto client =
std::make_shared<Client>("mongo://...");
- Too complex to talk about here.
- Read more if you're going to work on framework or library code. (Meyers book is good for this.)
- Some new stuff
- Some language oddities
- Some OO specifics
- Templating
- Compilers, CMake, and you
- Where to learn more?
- Random topics as time allows
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
long
, short
, char
, bool
, int
, double
, float
, long long
, unsigned ...
, a few more but not that many.
Constructors:
struct Point {int x; int y;};
Point p = Point {1, 2}; // if ctor is `explicit`
Point p = {1, 2};
Point p {1, 2};
Point p (1, 2); // needs ctor!
Primitives:
int x = {7};
int x {7};
int x (7);
int x = 7;
Preferred:
auto p = Point {1,2};
auto x = 7;
int main() {
Person x = Person("Ryan", "T");
Person y = x;
print(x);
print(y);
x = y;
}
void print(Person x) { ... }
int main() {
Person x = Person("Ryan", "T");
Person y = Person("Ryan", "S");
x = y; // ????
}
Person x = Person("Ryan", "T");
Person y = Person("Ryan", "S");
// x = y is "really":
x.operator=(y);
Foo x = ...;
x = 6; // x.operator=(int 6)
x = false; // x.operator=(bool false)
++x; // x.operator++()
x++; // x.operator++(int)
x << "Hello"; // x.operator<<(string "Hello")
x[7] = 8; // x.operator[](int 7)
x %= 7; // x.operator%=(int 7)
x == 7; // x.operator==(int 7)
x == x; // x.operator==(Foo x)
*x; // x.operator*()
x->foo(); // x.operator->().foo()
if(x) // x.operator bool()
x,6; // ๐
Too much syntax sugar causes cancer of the semicolon
struct Foo {
int i;
int operator ,(int other) {
return i + 10;
}
};
auto y = Foo{6};
std::cout << (y,7) << std::endl; // ๐
'nuff said?
int main() {
auto d = Database();
}
void print(Database d) { ... }
๐ฑ Deep Copy! ๐ฑ
- C only has pointers (but is always pass-by-value)
- Java and Python (implicitly) also only have pointers. (Except primitives which are passed by value. Usually.)
C++ plays by its own rules ๐ค
-
Pass by value (like C; pointers are values)
-
Unless signature takes a ref (then use that ref)
void process(Database d); void process(Database& d); void process(const Database& d);
int x = 7;
Pointers:
int* pointerToX = &x; // std::addressof(x);
*pointerToX = 10;
Refs:
int& refToX = x;
refToX = 10;
Results: x == 10
.
How did this work??
x[7] = 8;
It's just syntax sugar!
struct Foo {
int i;
int& operator[](int) {
return i;
}
}
Cool tidbit: Refs can never be nullptr
. Enforced at the language-level.
Refs can be evil ๐
void evil(int& x) { ++x; }
void doSomething() {
int x = 7;
evil(x);
}
Usually use const X&
to prevent calling non-consty things.
int main() {
auto d = Database();
}
void print(const Database& d) { ... }
๐ฏ No Deep-Copy ๐ฏ
void foo(Database* d) { ... }
void foo(Database d) { ... }
void foo(Database& d) { ... }
๐ ๐ฝ Can't have both ref and value overloads ๐ ๐ฝ
Q: When do I use pointers?
A: When you know that you don't own the thing
Q: What do I use instead?
A: Use std::shared_ptr
(ref-counted, some overhead)
A: or std::unique_ptr
(faster but awkwarder)
Don't use
new
(or at least never "nakednew
" ๐)
Instead of this:
Database* d = new Database(1,2,3);
... ๐ฅ?
delete d;
Do this:
auto d = std::make_shared<Database>(1,2,3);
Linkers and Compilers: Scheme together to share object code across multiple executables
No de-facto standards on
- directory-layout
- class/method/file naming
- documentation and where it goes
- what should be "header-only" and what should be a compiled library
๐ฉ
Unlike Java. Kinda like Python.
include/lib.hpp
:
#ifndef _HAVE_LIB_HPP
#define _HAVE_LIB_HPP
void add(int, int);
void sub(int, int);
#endif
src/lib.cpp
:
#include <lib.hpp>
void add(int a, int b) { return a + b; }
....
src/main.cpp
:
#include <lib.hpp>
int main() { return add(1,2); }
Header files:
- Class declarations
- Any templates and their definitions
- Rarely: inline function definitions
Impl files:
- Include needed header files
- Implementations
std::cout
mongo::client()
namespace mongo {
class client;
}
namespace std {
ostream& cout;
}
// new in c++17
namespace foo::bar {
...
}
// instead of:
namespace foo {
namespace bar {
...
}
}
#include <lib/Person.hpp>
// best-practice!
namespace {
void printPerson(const Person& p) { ... }
}
void Person::inspect() {
something();
}
(Don't pollute the global namespace.)
std::cout << 7;
Note that operator<<(std::ostream&,int)
isn't in the global namespace...
- Some new stuff
- Some language oddities
- Some OO specifics
- Templating
- Compilers, CMake, and you
- Where to learn more?
- Random topics as time allows
- Your types == built-in types
- Do as the
int
s do
struct Point {
int x;
int y;
}
auto origin = Point {0,0};
struct Point {int x; int y;};
Point p = Point {1, 2}; // if ctor is `explicit`
Point p = {1, 2};
Point p {1, 2};
Point p (1, 2); // needs ctor!
What you "want" to do from Java/Python:
struct Point {
int x;
int y;
Point(int x, int y) {
this->x = x;
this->y = y;
}
};
But: Then can't make x
and y
const
!
Solution:
struct Point {
const int x;
const int y;
Point(int x, int y)
: x{x}, y{y} {}
};
NB: Conventions usually have class members with leading underscore:
struct Point {
const int _x;
const int _y;
}
class Banner {
public:
Banner() = default;
// equiv:
// Banner() {}
private:
std::string msg = "Foo";
};
struct Point {
const int x;
const int y;
Point(int x, int y)
: x{x}, y{y} {}
const Point up() const {
return Point {this->x, this->y + 1}
}
}
const
is like a separate interface for your class.
void draw ( Point p) { }
void drawRef ( Point &p) { }
void drawConstRef (const Point &p) { }
const Point origin = {0,0};
Point up = origin.up();
const Point cup = origin.up();
// OK(ish)
draw(origin); draw(up); draw(cup);
drawRef(origin); // Error!
drawRef(up);
drawRef(cup); // Error!
// OK
drawConstRef(origin); drawConstRef(up); drawConstRef(cup);
Ugh:
struct Foo {
void enact() &; // 1
void enact() &&; // 2
}
void makeFoo() { auto out = Foo{}; return out; }
Foo f;
f.enact(); // 1
makeFoo().enact(); // 2
struct Point {
int x;
int y
Point(int x, int y, int z)
: x{x}, y{y}, z{z} {}
};
Point a = {0,0};
Point b = {1,1};
Point c = b; // copy
a = c; // assign
(Only occasionally necessary)
struct Point {
...
// Copy constructor
// Point a = b
Point(const Point& other)
: x{other.x}, y{other.y} {}
// Copy assignment
// c = b
Point& operator=(const Point& other) {
this->x = other.x;
this->y = other.y;
return *this;
}
};
Point a = {0,0};
Point b = {1,1};
Point c = b;
a = c;
struct Point {
...
~Point() {
std::cout << "Destructing" << std::endl;
}
}
This is how smart-pointers work.
- Classes: Default private
- Structs: Default public
- Create
public:
,private:
, andprotected:
sections for class-functions and members
class Printer { };
class SomeObject {
friend class Printer;
};
OO Principles:
- "Long-distance" friendships are dangerous.
- Consider Passkey idiom instead
class Figure { };
class BetterFigure : public Figure { };
class SomethingElse : private Figure { };
OO Principles:
- Hide unless designing to be visible
- Composition >> inheritance
struct Session {
virtual void rollback() { std::cout << "Session"; };
};
struct Causal : public Session {
void rollback() override { std::cout << "Causal"; }
};
struct Normal : public Session {
void rollback() override { std::cout << "Normal"; }
};
void enact(bool causal) {
std::unique_ptr<Session> session;
if (causal) {
session = std::make_unique<Causal>();
} else {
session = std::make_unique<Normal>();
}
session->rollback();
}
class QueuedJob {
public:
virtual void run() = 0;
};
class PrinterJob : public QueuedJob {
void run() override { }
};
void runJobs() {
std::vector<std::unique_ptr<QueuedJob>> jobs;
jobs.push_back(std::make_unique<PrinterJob>());
for(auto& job : jobs) {
job->run();
}
}
- They're not evil.
- Most compilers: no overhead except when thrown
- Uncaught exceptions cause the program to exit
Throw by value and catch by reference
void doSomething() {
throw std::logic_error("unknown value");
}
try {
doSomething();
} catch(const std::exception& ex) {
std::cerr << ex.what() << std::endl;
} catch(...) { // avoid except in framework code ...
}
- Some new stuff
- Some language oddities
- Some OO specifics
- Templating
- Compilers, CMake, and you
- Where to learn more?
- Random topics as time allows
- A bit fancier than text-substitution (but not by much!)
- Completely separate types ("duplicated" object-code)
- Templates need to be defined in headers
No "real" connection between these types/classes:
std::vector<int>
std::vector<std::string>
std::vector<MyClass>
Java version:
void blatz(List<? extends Foo> foos) {
for(Foo foo : foos) { explode(foo); }
}
"Direct translation" C++:
template<class T>
void blatz(const std::vector<Foo>& foos) {
for(auto& foo : foos) { explode(foo); }
}
More idiomatic:
template<class Foos>
void blatz(const Foos& foos) {
for(auto foo : foos) { explode(foo); }
}
No real way to give an "interface" to template parameters. Standards committee is working on it. Calling it concepts.
๐ฆ Hey C++ Does Have Duck-Typing! ๐ฆ
template<typename T>
struct MyStruct {
T myvar;
void incr() { myvar++; }
};
MyStruct<int> m1 {7};
std::cout << m1.myvar << std::endl;
m1.incr();
๐ฆ Hey C++ Does Have Duck-Typing! ๐ฆ
template<typename T>
struct MyStruct {
T myvar;
void incr() { myvar++; }
};
MyStruct<int> m1 {7};
std::cout << m1.myvar << std::endl;
m1.incr();
MyStruct<std::string> m2 {"Foo"};
std::cout << m1.myvar << std::endl;
Does this work?
๐ฆ Hey C++ Does Have Duck-Typing! ๐ฆ
template<typename T>
struct MyStruct {
T myvar;
void incr() { myvar++; }
};
MyStruct<int> m1 {7};
std::cout << m1.myvar << std::endl;
m1.incr();
MyStruct<std::string> m2 {"Foo"};
std::cout << m1.myvar << std::endl;
m2.incr();
Does this work?
error: cannot increment value of type
'std::__1::basic_string<char>'
myvar++;
~~~~~^
template<typename T>
struct MyClass {
T myvar;
void incr() { myvar++; }
};
// ๐
template<>
struct MyClass<std::string> {
std::string myvar;
void incr() { }
};
MyClass<int> m1 {7};
std::cout << m1.myvar << std::endl;
m1.incr();
MyClass<std::string> m2 {"Foo"};
std::cout << m1.myvar << std::endl;
m1.incr();
template<class T>
class TD;
void foo() {
auto x = "123";
TD<decltype(x)> xType;
}
Fancy:
error: implicit instantiation of
undefined template 'TD<const char *>'
- Some new stuff
- Some language oddities
- Some OO specifics
- Templating
- Compilers, CMake, and you
- Where to learn more?
- Random topics as time allows
๐ฑ๐คฎ๐คฏ๐ค๐
A Haiku about cmake:
CMake is garbage
CMake is garbage
CMake is garbage
-
Use an IDE at first (CLion is nice!)
-
CMake GUI
-
make VERBOSE=1
-
Use latest version of CLang you can (xcode 10 beta)
sudo xcode-select -s \ /Applications/Xcode-beta.app/Contents/Developer
- Learn to read the matrix
- SFINAE
- Grok how header files, object files, and linkers play together
- Use a STL Pretty-Printer (one header file gives you
<<
for many built-in types)
CMake is garbage
- Some new stuff
- Some language oddities
- Some OO specifics
- Templating
- Compilers, CMake, and you
- Where to learn more?
- Random topics as time allows
- Most books written for people who already know some C++
- The C++ Programming Language, 4th Edition ($40)
- Meyers Effective Modern C++ ($40)
- Good for move, threading, some templating
- "C++ Coding Standards" by Andrei Alexandrescu ($50 ๐ผ)
- Some new stuff
- Some language oddities
- Some OO specifics
- Templating
- Compilers, CMake, and you
- Where to learn more?
- Random topics as time allows
This is C++. There are no simple questions, and even fewer simple answers.
- Ask on Slack
#cxx-discuss
! Everybody is really friendly and helpful. No n00b-shaming. Much shaming of the language (and of CMake) - Thanks to Henrik's Open-Source Project for impress.js for powering this presentation!
- ABIs
using X
,using Y = Z
, don't sayusing X
in headers- Implicit conversions
explicit
constructorsconstexpr
assert
- passkey idiom
- pimpl idiom
My Reference: 8745WUT2P8NHYK1JGP5F4