C++11coreintermediate
noexcept Specifier (C++11 Addition)
C++11 · Modern Revolution · Compiler flag: -std=c++11
Explanation
Specifies whether a function can throw exceptions, aiding optimization.
Real-World Scenario
Optimize performance in a critical system by guaranteeing no exceptions.
Quick Snippet
snippet.cpp
void safeFunc() noexcept {}Full Example
noexcept_specifier.cpp
// CodeNebula - C++11 Example: noexcept Specifier and Operator
// Compile: g++ -std=c++11 -Wall -Wextra -o example noexcept_specifier.cpp
// Demonstrates the noexcept specifier and operator. noexcept promises a
// function won't throw exceptions, enabling compiler optimizations and
// ensuring move operations work correctly with STL containers.
#include <iostream>
#include <vector>
#include <string>
#include <type_traits>
#include <utility>
// ------------------------------------------------------------------
// 1. noexcept specifier on functions
// ------------------------------------------------------------------
void safeFunction() noexcept
{
// Guaranteed not to throw
std::cout << " safeFunction: no exceptions possible" << std::endl;
}
void riskyFunction() // may throw (implicit noexcept(false))
{
std::cout << " riskyFunction: might throw" << std::endl;
}
// Conditional noexcept
template <typename T>
void swap_values(T& a, T& b) noexcept(noexcept(T(std::move(a))))
{
T temp(std::move(a));
a = std::move(b);
b = std::move(temp);
}
// ------------------------------------------------------------------
// 2. Class with noexcept move operations (critical for STL)
// ------------------------------------------------------------------
class Buffer {
int* data_;
std::size_t size_;
std::string tag_;
public:
Buffer(const std::string& tag, std::size_t n)
: data_(new int[n]()), size_(n), tag_(tag)
{
std::cout << " [Ctor] " << tag_ << std::endl;
}
// Copy (might throw due to allocation)
Buffer(const Buffer& o) : data_(new int[o.size_]), size_(o.size_), tag_(o.tag_)
{
std::copy(o.data_, o.data_ + size_, data_);
std::cout << " [Copy] " << tag_ << std::endl;
}
// Move (noexcept: no allocation, just pointer swap)
Buffer(Buffer&& o) noexcept
: data_(o.data_), size_(o.size_), tag_(std::move(o.tag_))
{
o.data_ = nullptr;
o.size_ = 0;
std::cout << " [Move] " << tag_ << std::endl;
}
// Move assignment (noexcept)
Buffer& operator=(Buffer&& o) noexcept
{
if (this != &o) {
delete[] data_;
data_ = o.data_; size_ = o.size_; tag_ = std::move(o.tag_);
o.data_ = nullptr; o.size_ = 0;
}
return *this;
}
~Buffer() { delete[] data_; }
const std::string& tag() const { return tag_; }
};
int main()
{
// ------------------------------------------------------------------
// 1. noexcept operator (compile-time query)
// ------------------------------------------------------------------
std::cout << "=== noexcept operator ===" << std::endl;
std::cout << " noexcept(safeFunction()) : "
<< noexcept(safeFunction()) << std::endl;
std::cout << " noexcept(riskyFunction()) : "
<< noexcept(riskyFunction()) << std::endl;
std::cout << " noexcept(1 + 2) : "
<< noexcept(1 + 2) << std::endl;
std::cout << " noexcept(new int) : "
<< noexcept(new int) << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 2. noexcept functions
// ------------------------------------------------------------------
std::cout << "=== noexcept functions ===" << std::endl;
safeFunction();
riskyFunction();
std::cout << std::endl;
// ------------------------------------------------------------------
// 3. noexcept move enables vector optimization
// ------------------------------------------------------------------
std::cout << "=== Vector reallocation (noexcept move) ===" << std::endl;
std::cout << " With noexcept move, vector uses move during realloc:" << std::endl;
std::vector<Buffer> vec;
vec.reserve(2);
vec.emplace_back("A", 10);
vec.emplace_back("B", 10);
std::cout << " -- Triggering reallocation --" << std::endl;
vec.emplace_back("C", 10); // reallocation: moves A,B (not copies!)
std::cout << std::endl;
std::cout << " Vector contents:" << std::endl;
for (const auto& b : vec) {
std::cout << " " << b.tag() << std::endl;
}
std::cout << std::endl;
// ------------------------------------------------------------------
// 4. Type traits for noexcept
// ------------------------------------------------------------------
std::cout << "=== Move noexcept traits ===" << std::endl;
std::cout << " is_nothrow_move_constructible<Buffer>: "
<< std::is_nothrow_move_constructible<Buffer>::value << std::endl;
std::cout << " is_nothrow_move_constructible<string>: "
<< std::is_nothrow_move_constructible<std::string>::value << std::endl;
std::cout << std::endl;
// ------------------------------------------------------------------
// 5. Conditional noexcept with swap
// ------------------------------------------------------------------
std::cout << "=== Conditional noexcept ===" << std::endl;
int a = 1, b = 2;
swap_values(a, b);
std::cout << " After swap: a=" << a << ", b=" << b << std::endl;
std::cout << " noexcept(swap_values(a,b)): "
<< noexcept(swap_values(a, b)) << std::endl;
return 0;
}
/*
Expected output:
=== noexcept operator ===
noexcept(safeFunction()) : 1
noexcept(riskyFunction()) : 0
noexcept(1 + 2) : 1
noexcept(new int) : 0
=== noexcept functions ===
safeFunction: no exceptions possible
riskyFunction: might throw
=== Vector reallocation (noexcept move) ===
With noexcept move, vector uses move during realloc:
[Ctor] A
[Ctor] B
-- Triggering reallocation --
[Ctor] C
[Move] A
[Move] B
Vector contents:
A
B
C
=== Move noexcept traits ===
is_nothrow_move_constructible<Buffer>: 1
is_nothrow_move_constructible<string>: 1
=== Conditional noexcept ===
After swap: a=2, b=1
noexcept(swap_values(a,b)): 1
*/
Run command
g++ -std=c++11 -Wall -Wextra -o example noexcept_specifier.cpp