Ключевое слово, явно обозначающее нулевой указатель
void foo(int) { cout << "int" << endl; }
void foo(void*) { cout << "void*" << endl; }
int main() {
foo(0); // int
foo(nullptr); // void*
}
Проверка условия на этапе компиляции
// Compilation error on x64 configuration
static_assert(sizeof(void *) == 4,
"64-bit code generation is not supported.");
template<class T, int C> class Stack {
T* m_pBuffer[C];
static_assert(C > 0, "Stack capacity must be positive.");
public:
// Member function definition
};
const int g_Count = 150;
int main() {
static_assert(g_Count < 100,
"Count must not exceed 100."); // Compilation error
Stack<int, 10> s1; // OK
Stack<int, 0> s2; // Compilation error
}
Кортеж из нескольких элементов
// Explicit types and initialization
std::tuple<int, double, std::string> t1(42, 3.14, "foo");
// Deduced types, same as above
auto t2 = std::make_tuple(42, 3.14, std::string("foo"));
// Explicit retrieval of elements
int i = std::get<0>(t2);
double d = std::get<1>(t2);
std::string s = std::get<2>(t2);
// Batch retrieval of all elements, same as above
std::tie(i, d, s) = t2;
// Batch retrieval of several elements
std::tie(i, std::ignore, s) = t2;
void FindFurthestVertices(const Graph& graph, int& v1, int& v2, double& d);
void foo(const Graph& graph)
{
int v1, v2;
double d;
FindFurthestVertices(graph, v1, v2, d);
}
std::tuple<int, int, double> FindFurthestVertices(const Graph& graph);
void foo(const Graph& graph)
{
int v1, v2;
double d;
std::tie(v1, v2, d) = FindFurthestVertices(graph);
}
Обёртка для встроенных массивов в стиле C++
const int count = 5;
// Supports initialization lists
std::array<int, count> a = { 2, 3, 5, 7, 11 };
// Guaranteed to be stored just like native array
static_assert(sizeof(a) == count * sizeof(int), "Non-standard");
// Supports copying and assignment
std::array<int, 5> b = a;
// Some useful built-in methods
a.fill(0);
// Supports comparison
if (a < b) std::cout << "Works!" << std::endl; // Really works
// Provide direct access to data
int* pB = b.data();
// Supports common STL-container interface
std::cout << a.size() << std::endl; // 5
for (auto i = b.cbegin(); i != b.cend(); ++i) std::cout << *i << " ";
typedef double Color[3];
Color CropColor(Color color) // Shallow copy of built-in array
{
for (int i = 0; i < 3; ++i)
{
// Crop into [0; 1] range
color[i] = std::max(0.0, std::min(color[i], 1.0));
}
return color; // Cannot return built-in array
}
typedef std::array<double, 3> Color;
Color CropColor(Color color) // Deep copy of std::array
{
for (int i = 0; i < 3; ++i)
{
// Crop into [0; 1] range
color[i] = std::max(0.0, std::min(color[i], 1.0));
}
return color; // Return is ok
}
Практически всегда следует пользоваться std::array. Возможные исключения:
enum Status;
const char* GetErrorMessage(Status status)
{
static const char* messages[] = {
"OK", // STATUS_OK
"Unknown error", // STATUS_ERROR
"Not enough memory", // STATUS_MEMORY
"Filesystem error" // STATUS_IO
};
return messages[status];
}
Из докалада Скотта Мейерса "Why C++ Sails When the Vasa Sank", почему С++ так популярен, несмотря на сложность
Resource Acquisition Is Initialization
void WriteToFile(const std::string& message)
{
// mutex to protect file access
static std::mutex mutex;
// lock mutex before accessing file
std::lock_guard<std::mutex> lock(mutex);
// try to open file
std::ofstream file("example.txt");
if (!file.is_open())
throw std::runtime_error("unable to open file");
// write message to file
file << message << std::endl;
// file will be closed 1st when leaving scope (regardless of exception)
// mutex will be unlocked 2nd (from lock destructor) when leaving
// scope (regardless of exception)
}
Владение ресурсом ассоциируется с временем жизни объекта
Примеры:
Класс, который выполняет заданную функцию в деструкторе. Позволяет использовать идиому RAII там, где её не хватает.
class ScopeGuard
{
public:
ScopeGuard(std::function<void()> f) : m_f(f) {}
~ScopeGuard()
{
if (m_f)
{
try
{
m_f();
}
catch (std::exception&)
{
// Some assertions or logging here
}
}
}
// Disable copy operations, enable move operations
private:
std::function<void()> m_f;
};
class IHardware
{
public:
virtual double GetPosition() const = 0;
virtual void SetPosition(double position) = 0;
virtual bool TakeSnapshot() = 0; // Might fail
};
bool DoScan(double step, int count, IHardware* pHardware)
{
double startPos = pHardware->GetPosition();
double pos = startPos;
for (int i = 0; i < count; i++)
{
pos += step;
pHardware->SetPosition(pos);
pHardware->TakeSnapshot();
}
pHardware->SetPosition(startPos);
return true;
}
class IHardware
{
public:
virtual double GetPosition() const = 0;
virtual void SetPosition(double position) = 0;
virtual bool TakeSnapshot() = 0; // Might fail
};
bool DoScan(double step, int count, IHardware* pHardware)
{
double startPos = pHardware->GetPosition();
double pos = startPos;
for (int i = 0; i < count; i++)
{
pos += step;
pHardware->SetPosition(pos);
if (!pHardware->TakeSnapshot()) return false;
}
pHardware->SetPosition(startPos);
return true;
}
class IHardware
{
public:
virtual double GetPosition() const = 0;
virtual void SetPosition(double position) = 0;
virtual bool TakeSnapshot() = 0; // Might fail
};
bool DoScan(double step, int count, IHardware* pHardware)
{
double startPos = pHardware->GetPosition();
double pos = startPos;
for (int i = 0; i < count; i++)
{
pos += step;
pHardware->SetPosition(pos);
if (!pHardware->TakeSnapshot())
{
pHardware->SetPosition(startPos); // DRY!
return false;
}
}
pHardware->SetPosition(startPos);
return true;
}
class IHardware
{
public:
virtual double GetPosition() const = 0;
virtual void SetPosition(double position) = 0;
virtual bool TakeSnapshot() = 0; // Might fail
};
bool DoScan(double step, int count, IHardware* pHardware)
{
double startPos = pHardware->GetPosition();
double pos = startPos;
ScopeGuard posGuard([&] () { pHardware->SetPosition(startPos); });
for (int i = 0; i < count; i++)
{
pos += step;
pHardware->SetPosition(pos);
if (!pHardware->TakeSnapshot()) return false;
}
return true;
}
cmsHPROFILE cmsCreateProfilePlaceholder(cmsContext ContextID);
cmsBool cmsCloseProfile(cmsHPROFILE hProfile);
void CreateAndSaveColorProfile(const std::string& path)
{
cmsHPROFILE hProfile = cmsCreateProfilePlaceholder(0);
ScopeGuard profileGuard([&] () { cmsCloseProfile(hProfile); });
// Create and save profile, both operations might throw
}
class ScopeGuard
{
...
void Discard()
{
m_f = nullptr;
}
void Apply()
{
m_f();
m_f = nullptr;
}
...
};
bool DoScan(double step, int count, IHardware* pHardware)
{
double startPos = pHardware->GetPosition();
double pos = startPos;
ScopeGuard posGuard([&] () { pHardware->SetPosition(startPos); });
for (int i = 0; i < count; i++)
{
pos += step;
pHardware->SetPosition(pos);
if (!pHardware->TakeSnapshot()) return false;
}
posGuard.Apply();
// Time consuming operation, like saving snapshots
return true;
}
class IImageStitcher
{
public:
virtual msa::Status Initialize() = 0;
virtual msa::Status StitchImages(const msa::ICollection* pImages) = 0;
virtual const char* GetStatusDescr() const = 0;
};
bool Stitch(IImageStitcher* pStitcher)
{
msa::ICollection* pImages;
// Populate collection with images
pStitcher->Initialize();
pStitcher->StitchImages(pImages);
return true;
}
bool Stitch(IImageStitcher* pStitcher)
{
msa::ICollection* pImages;
// Populate collection with images
if (pStitcher->Initialize() != msa::STATUS_OK)
{
std::cout << pStitcher->GetStatusDescr() << std::endl;
return false;
}
if (pStitcher->StitchImages(pImages) != msa::STATUS_OK)
{
std::cout << pStitcher->GetStatusDescr() << std::endl;
return false;
}
return true;
}
bool Stitch(IImageStitcher* pStitcher)
{
msa::ICollection* pImages;
// Populate collection with images
ScopeGuard errorGuard([&] () {
std::cout << pStitcher->GetStatusDescr() << std::endl;
});
if (pStitcher->Initialize() != msa::STATUS_OK) return false;
if (pStitcher->StitchImages(pImages) != msa::STATUS_OK) return false;
errorGuard.Discard();
return true;
}
bool InitializeData(Data& data)
{
ScopeGuard defaultGuard([&] () {
data = Data::GetDefaultValue();
});
if (!DoFirstInitializationStep(data)) return false;
if (!DoSecondInitializationStep(data)) return false;
if (!DoThirdInitializationStep(data)) return false;
defaultGuard.Discard();
return true;
}
void SaveData(const Data& data)
{
SaveDataToDatabase(data); // Might throw
ScopeGuard databaseGuard([&] () { RemoveDataFromDatabase(data); });
SaveDataToDisk(data); // Might throw
ScopeGuard diskGuard([&] () { RemoveDataFromDisk(data); });
SaveDataToCloud(data); // Might throw
diskGuard.Discard();
databaseGuard.Discard();
}
Многопоточность в C++11
Огромное количество вариантов сборки
Сборка всех библиотек для конкретного компилятора и конкретной платформы
Отдельный NuGet-пакет для каждой библиотеки boost для всех вариантов конкретного компилятора
Встроенное расширение для Visual Studio
Репозиторий содержит .nupkg-файлы. Можно использовать даже локальную папку.
Пакеты доступны на NuGet-сервере (пока тестовый режим)
Пакеты настраиваются в свойствах проекта
Необходимо продублировать настройки CRT
boost сам подключает необходимые .lib-файлы с помощью директив #pragma в зависимости от ряда макросов