Open In App

C++ 23 – <flat_set> Header

Last Updated : 24 Apr, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

<flat_set> is a header file that provides the implementation of the std::flat_set container class in C++, which is a sorted associative container that stores unique elements and allows for fast access, insertion, and removal of elements.

The flat_set is a container similar to the set but its elements are stored contiguously in memory. This can provide faster iteration times and better cache locality compared to std::set, especially when the container is relatively small or its elements are trivially copy-able.

Syntax of std::flat_set

flat_set <T, Compare, Allocator> object_name;

where,

  •  T: The type of elements to be stored in the flat_set.
  • Compare: An optional parameter that specifies a comparison function to order the elements. If not provided, std::less is used by default.
  • Allocator: An optional parameter that specifies the allocator to use for memory management. If not provided, the default allocator is used.

std::flat_set Initialization

We can initialize the flat_set object in multiple different ways. Some of them are as follows:

1. Using the Default Constructor

If we don’t provide any parameter in the declaration, the default constructor is used to initialize the std::flat_set object.

Example

flat_set <int> object_name;

2. Using the Initializer List

We can provide the elements in the initializer list to initialize the std::flat_set object.

Example

flat_set <int> object_name { 1,5,4,2,3,9,8 };

Note: The time complexity of the initialization of flat_set using a number of elements is O (nlogn) which is required for sorting and sorted insertion.

3. Using the Range Constructor with a Pair of Iterators

We can initialize the std::flat_set object using the range specified by starting iterator and ending iterator.

Example

flat_set <data_type> object_name(startingIterator, endingIterator);

4. Using the Move Assignment Operator

The advantage of using the move assignment operator to initialize the flat_set object is that it avoids unnecessary copies of data by directly pointing the assigned object to the memory location where the data is already stored.

Example

flat_set <datatype> object_name;
object_name = move(prev_object);

5. Using the Assignment Operator

It is one of the simplest ways to initialize the flat_set object using another already existing flat_set object.

Example

flat_set <data_type> object_name;
object_name = prev_object;

std::flat_set Member Functions

The std::flat_set class contains the function to perform different tasks some of which are as follows:

Iterators

Iterators are used to access the elements of the flat_set container or iterate through the container. The following member functions are used to get the iterator:

S.No

Function

Description

1

begin() It returns the iterator to the first element in the flat_set.

2

end() It returns the iterator to the last elements in the flat_set.

3

rbegin() It returns the reverse iterator to the last element.

4

rend() It returns the reverse iterator to the first element.

Example 1: Traversing flat set container elements using iterators.

C++




// C++ program to illustrate the flat_set traversal
#include <flat_set>
#include <iostream>
using namespace std;
 
// driver code
int main()
{
 
    // initializing using initializer list
    flat_set<int> fset{ 4, 8, 1, 9, 2 };
 
    // traversing using loops
    cout << "Elements in the fset container:\n";
    for (auto i = fset.begin(); i != fset.end(); i++) {
        cout << *i << " ";
    }
    return 0;
}


Output

Elements in the fset container:
1 2 4 8 9

Capacity

These functions are used to return the size-related values.

S.No.

Function

Description

1

empty() It returns true if the set is empty, otherwise returns false.

2

size() It returns the number of elements currently present in the flat set.

3

max_size() It returns the maximum possible size of the flat set.

Example 2: C++ Program to find the size and max_size of the flat set container.

C++




// C++ program to find the size and allocated size of the
// flatset container
#include <cstdlib>
#include <flat_set>
#include <iostream>
using namespace std;
 
// driver code
int main()
{
 
    // initializing using initializer list
    flat_set<int> fset{ 4, 8, 1, 9, 2 };
 
    // checking if the fset is empty
    if (fset.empty()) {
        cout << "The fset is empty";
        exit(0);
    }
 
    // traversing using loops
    cout << "Elements in the fset container:\n";
    for (auto i = fset.begin(); i != fset.end(); i++) {
        cout << *i << " ";
    }
    printf("\n");
 
    // Size of the container
    cout << "Size of the Container: " << fset.size()
         << endl;
    cout << "Maximum Possible size of the container: "
         << fset.max_size() << endl;
 
    return 0;
}


Output

Elements in the fset container:
1 2 4 8 9 
Size of the Container: 5
Allocated size of the container: 1073741823

Note: The maximum possible size returned by the max_size() function may change depending on the machine and implementation.

Modifiers

The modifier member functions are used to insert, remove and update the flat set container elements. Some of them are as follows:

S. No.

Function Name

Description

Time Complexity

1.

emplace() It is used for the in-place insertion of the element in the container.

O(n)

2.

insert() It is used for the simple insertion of the element in the flat set.

O(n)

3.

erase() It is used to remove the element or a range of elements from the flat set.

O(n)

4.

swap() It is used to swap two flat sets of the same type

O(1)

5.

clear() It is used to clear all the elements of the flat_set container

O(n)

Example 3: C++ Program to insert, remove, and clear data in std::flat_set Container

C++




// C++ program to illustrate the use of insert(), erase(),
// clear(), emplace() functions of std::flat_set class
#include <flat_set>
#include <iostream>
using namespace std;
 
// utility function to print the flat_set
void printfset(flat_set<int>& fset)
{
    for (auto i : fset) {
        cout << i << " ";
    }
 
    cout << endl;
}
 
// driver code
int main()
{
    flat_set<int> fset{ 4, 8, 1, 9, 2 };
 
    cout << "Initial Elements in fset: ";
    printfset(fset);
 
    // inserting elements
    fset.emplace(3);
    fset.insert(5);
 
    cout << "Elements in fset after Insertion: ";
    printfset(fset);
 
    // deleting elements
    fset.erase(8);
    fset.erase(9);
 
    cout << "Elements in fset after Deletion: ";
    printfset(fset);
 
    // clearing the fset container
    cout << "Size of fset: " << fset.size() << endl;
    fset.clear();
    cout << "Size of fset after clear(): " << fset.size();
 
    return 0;
}


Output

Initial Elements in fset: 1 2 4 8 9 
Elements in fset after Insertion: 1 2 3 4 5 8 9 
Elements in fset after Deletion: 1 2 3 4 5 
Size of fset: 5
Size of fset after clear(): 0

Basic flat_set Operations

These functions provide the basic flat set operations:

S. No.

Function

Description

Time Complexity

1.

find() Searches the flat_set for the given element and returns an iterator to it. If not found, returns the iterator to the end.

O (logn)

2.

count() Returns the number of occurrences of an element in the flat_set. Since flat_set only stores unique elements, the count can be either 0 or 1.

O (logn)

3.

contains() It returns true if the flat set contains the given element, otherwise, returns false.

O (logn)

4.

lower_bound() It returns the iterator to the first element which is equivalent or greater than the given value

O (logn)

5.

upper_bound() It returns the iterator to the first element which is equal to or greater than the given element.

O (logn)

Example of std::flat_set

The below program demonstrates some of the basic operations that can be performed on a std::flat_set, such as inserting, searching, and removing elements, as well as iterating over the elements.

C++




// C++ Program to implement flat_set container and perform
// the set operations on it
#include <algorithm>
#include <flat_set>
#include <iostream>
#include <iterator>
#include <vector>
using namespace std;
 
// utility function to print the flat_set
void printfset(flat_set<int>& fset)
{
    ostream_iterator<int> it_out(cout, " ");
    copy(fset.begin(), fset.end(), it_out);
    cout << endl;
}
 
// driver code
int main()
{
 
    // declaring a vector with random elements to initialize
    // the flat_set
    vector<int> vec{ 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5 };
 
    // defining a flat_set container with the vector
    // iterators
    flat_set<int> fset(begin(vec), end(vec));
 
    // printing the fset elements
    cout << "Elements in the flat_set: ";
    printfset(fset);
 
    // size of fset container
    cout << "Number of elements in the flat_set: "
         << fset.size() << endl;
 
    // checking if 7 is present in the container using
    // find()
    if (fset.find(7) == fset.end()) {
        cout << "7 is not present." << endl;
    }
    else {
        cout << "7 is present." << endl;
    }
 
    // inserting an element to the fset
    fset.insert(7);
    cout << "AFTER INSERTING 7!!" << endl;
    // checking if 7 is present using contains()
    if (fset.contains(7)) {
        cout << "7 is present" << endl;
    }
    else {
        cout << "7 is not present." << endl;
    }
 
    // upper_bound and lower_bound
    cout << "Upper Bound: " << *fset.upper_bound(3) << endl;
    cout << "Lower Bound: " << *fset.lower_bound(3) << endl;
 
    return 0;
}


Output

Elements in the flat_set: 1 2 3 4 5 6 9 
Number of elements in the flat_set: 7
7 is not present.
AFTER INSERTING 7!!
7 is present
Upper Bound: 4
Lower Bound: 3

Note: C++23 is not yet a fully released standard and therefore there is no widely available compiler that fully supports all of its features. However, some compilers may have experimental or partial support for certain C++23 features.

If you want to experiment with the latest C++23 features, you may want to consider using a compiler that supports experimental or partial features. Some popular compilers, such as GCC and Clang, offer experimental support for some C++23 features. However, keep in mind that experimental features may not be fully stable or feature-complete, and may be subject to change in future updates.

How flat_set is Implemented

The flat_set container is implemented as a sorted associative container, which means that its elements are sorted according to a comparison function.

However, unlike the standard set container, the flat_set stores its elements in a contiguous memory block, making it more efficient in terms of cache locality and memory usage. This is achieved by using a vector as the underlying storage for the flat_set and ensuring that the elements are always sorted in the vector.

  • When an element is inserted into the flat_set, it is first located in the vector using binary search. If the element is not found, it is inserted at the appropriate position in the vector using a move operation, which preserves the sorted order of the vector.
  • Similarly, when an element is removed from the flat_set, it is located in the vector using binary search and removed from the vector using a move operation.

Since the flat_set uses a vector as its underlying storage, it provides constant-time access to its elements, making it faster than the standard set container in some cases. However, the flat_set may be slower than the set container when it comes to the insertion and removal of elements, especially for large data sets.

Properties of the flat_set

  • Elements are stored in sorted order, just like in a set.
  • It uses a flat memory layout, meaning that elements are stored contiguously in memory, making it more cache-friendly and potentially faster for certain operations.
  • It does not allow duplicates, just like set.
  • It has a smaller memory footprint than set because it does not need to store additional pointers to maintain the tree structure.

Advantages of flat_set

  • Since the elements are stored contiguously in memory, it can be faster than set for operations like iteration and finding elements.
  • It has a smaller memory footprint than set, which can be advantageous in memory-constrained environments.
  • It is a more cache-friendly data structure than set, which can lead to faster access times for frequently accessed elements.

Disadvantages of flat_set

  • It has a slower insertion time than std::set because it needs to shift elements in the array to make room for the new element, which can take O(N) time in the worst case.
  • It has a fixed capacity, which means that if the capacity is exceeded, the container needs to be reallocated and copied to a larger array, which can be expensive in terms of time and memory.


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads