Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different noexcept property for std containers in different Compilers

Tags:

c++

std

c++17

Is the move-constructors noexcept property for containers implementation defined? I just found out that the following will work in clang but not in gcc or msvc++:

std::vector<std::vector<std::unique_ptr<int>>> vector_a;
std::vector<std::stack<std::unique_ptr<int>>> vector_b;
vector_a.reserve(10);  // this works in all tested compilers
vector_b.reserve(10);  // this only works in clang

My question is, if this is caused by an incomplete implementation of the standard or if it is simply not defined (on purpose?).

I tested a few of the standard containers:

#include <iostream>
#include <deque>
#include <vector>
#include <queue>
#include <stack>

int main() {
    std::cout << "Deque: " << std::is_nothrow_move_constructible<std::deque<float>>::value << std::endl;
    std::cout << "Vector: " << std::is_nothrow_move_constructible<std::vector<float>>::value << std::endl;
    std::cout << "Queue: " << std::is_nothrow_move_constructible<std::queue<float>>::value << std::endl;
    std::cout << "Stack: " << std::is_nothrow_move_constructible<std::stack<float>>::value << std::endl;
}

gcc 7.2.1:

Deque: 0
Vector: 1
Queue: 0
Stack: 0

clang 5.0.0:

Deque: 1
Vector: 1
Queue: 1
Stack: 1

Microsoft C/C++ Version 19.00.23506 for x64:

Deque: 0
Vector: 1
Queue: 0
Stack: 0

EDIT

Results for queue and stack using a vector as underlying container:

std::cout << "Vector Stack: " << std::is_nothrow_move_constructible<std::stack<float, std::vector<float>>>::value << std::endl;
std::cout << "Vector Queue: " << std::is_nothrow_move_constructible<std::queue<float, std::vector<float>>>::value << std::endl;

gcc 7.2.1:

Vector Stack: 1
Vector Queue: 1

clang 5.0.0:

Vector Stack: 1
Vector Queue: 1

Microsoft C/C++ Version 19.00.23506 for x64:

Vector Stack: 1
Vector Queue: 1
like image 431
BoshWash Avatar asked Feb 18 '26 10:02

BoshWash


1 Answers

stack and queue are not containers; they are container adapters. They use a container type that you give them as a template argument. By default, they use std::deque.

As such, they forward the noexcept behavior of the container they're adapting. So if deque throws on move, so too will a stack that uses a deque. Actually, container adapters don't forward the noexcept behavior of their component containers. Or at least, they aren't required to by the standard.

As for the noexcept status of actual containers, vector is required to have a noexcept move (this was a C++17 change; there were no requirements previously). The rest are implementation-dependent.

like image 69
Nicol Bolas Avatar answered Feb 19 '26 23:02

Nicol Bolas