Double-ended or deque queues are sequence containers that can grow and contract on both ends. They are similar to vectors but also more effective when elements are added or removed at the beginning or finish. In contrast to vectors, contiguous storage allocation is not always assured. In this article, we will discuss the difference between deque::assign and deque::at in C++. Before discussing their difference, we must know about the deque::assign and deque::at in C++ with their syntax, parameters, and examples.
What is the deque::assign in C++?
The member function deque::assign resizes a std::deque as needed and substitutes new contents for each of its elements. After the preceding elements have been removed, the deque is populated with new values from a range, an initializer list, or repeating values of a specified count. This function is particularly useful when reinitializing a deque's contents in a single step. As opposed to direct assignments, the size of the deque is assured to match the provided data when assigning. Rather of examining the deque for borders, it modifies its entire structure.
Syntax:
It has the following syntax:
deque.assign(first, last); // Assigns elements from range [first, last)
deque.assign(n, value); // Assigns n copies of value
Purpose: The deque's current contents can be replaced and its size can be adjusted by using this function.
Functionality:
- It eliminates all of the deque's current components.
- It adds additional components according to the provided parameters.
- It resizes the deque to accommodate the updated contents.
- Give a variety of elements: give (first, last)
- Assign repeating values: (count, value) assign
- Designate a list of initialisers: assign({value1, value2,...})
Overloads are:
Example:
Let us take an example to illustrate the deque::assign in C++.
std::deque<int> dq;
dq.assign(5, 10); // Assign 5 elements with a value of 10
// dq now contains: [10, 10, 10, 10, 10]
What is the deque::at?
The deque::at function use these functions to access or modify elements in a std::deque at a specific index while performing bounds checking. By raising a std::outofrange exception if the specified index is out of range, it guarantees that elements can be accessed safely. The function does not change the deque's size or structure; it only modifies objects that are already there. It can be used for both reading and modifying values. It is ideal in circumstances when index validity cannot be guaranteed because it offers greater security than the subscript operator () due to bounds checking.
Syntax:
It has the following syntax:
deque.at(index)
T& at(size_t index); // Returns a reference to the element at index
const T& at(size_t index) const; // For constant deques
Purpose: It offers bounds-checked access to the element at a given index.
The ability to function:
- It gives back a reference to the element located at the specified place.
- If the index is invalid, it raises a std::outofrange exception.
- It enables the element to be read and modified at the designated location.
Using:
Example:
Let us take an example to illustrate the deque::at in C++.
std::deque<int> dq = {10, 20, 30};
int value = dq.at(1); // Access element at index 1
dq.at(2) = 50; // Modify element at index 2
// dq now contains: [10, 20, 50]
Key differences between deque::assign and deque::at in C++:
There are several key differences between deque::assign and deque::at in C++. Some main differences are as follows:
| Aspects | Deque::assign | Deque::at |
|---|---|---|
| Definition | The deque container's current contents are replaced with new ones using this method. | It is used to give back a reference to the deque container object's element at position n. |
| Purpose | It adds new items to the deque and replaces all its parts. | It alters or accesses an element at a certain index. |
| Effect | Changes all of the present items and resizes the deque. | It has no effect on the deque's dimensions or structure. |
| Parameters | It takes an initializer list, range, or count-value pair as input. | Only one index is accepted as an argument. |
| Exception | It doesn't make exceptions in typical circumstances. | If the index is not valid, std::outofrange is thrown. |
| Modification | It replaces every element in the deque. | It interacts with just one element. |
| Typical usage | Reset or reinitialize the contents of the deque. | Safely accessing or changing individual components. |
| Bounds checking | Not relevant (replaces contents). | It ensures secure access by performing bounds checking. |
| Impact | It restarts the deque and may alter its size. | Only reads or changes an already-existing element. |
| Complexity | The complexity of it is linear. | It never gets any simpler. |
| Return value | It has no return type. | It gives back a reference to the element at the specified location. |
Example Usage:
Example 1:
Let us take an example to illustrate the deque::assign and deque::at in C++.
#include <iostream>
#include <deque>
#include <stdexcept> // For std::out_of_range
int main() {
// Example 1: Using `deque::assign`
std::deque<int> dq;
// Assign 5 elements with the value 10
dq.assign(5, 10);
std::cout << "Deque after assign: ";
for (const auto& elem : dq) {
std::cout << elem << " "; // Output: 10 10 10 10 10
}
std::cout << "\n";
// Assign a range of values from an initializer list
dq.assign({1, 2, 3, 4, 5});
std::cout << "Deque after reassigning from initializer list: ";
for (const auto& elem : dq) {
std::cout << elem << " "; // Output: 1 2 3 4 5
}
std::cout << "\n";
// Example 2: Using `deque::at`
try {
std::cout << "Element at index 2: " << dq.at(2) << "\n"; // Output: 3
// Modify an element using at()
dq.at(2) = 99;
std::cout << "Deque after modifying index 2: ";
for (const auto& elem : dq) {
std::cout << elem << " "; // Output: 1 2 99 4 5
}
std::cout << "\n";
// Attempt to access an out-of-bounds index
std::cout << "Accessing out-of-bounds index: " << dq.at(10) << "\n";
} catch (const std::out_of_range& e) {
std::cout << "Exception: " << e.what() << "\n"; // Output: Exception: deque::_M_range_check: __n (which is 10) >= this->size() (which is 5)
}
return 0;
}
Output:
Deque after assign: 10 10 10 10 10
Deque after reassigning from initializer list: 1 2 3 4 5
Element at index 2: 3
Deque after modifying index 2: 1 2 99 4 5
Accessing out-of-bounds index: Exception: deque::_M_range_check: __n (which is 10)>= this->size() (which is 5)
Explanation:
- First, replaces the contents of the deque with elements from an initializer list or assigns a predetermined number of elements.
- After that, makes the deque resize to fit the updated data.
- Alters or accesses specific items safely.
- An exception is raised if the supplied index is not valid.
Example 2:
Let us take another example to illustrate the deque::assign and deque::at in C++.
#include <iostream>
#include <deque>
int main() {
// Example: Using `deque::assign`
std::deque<std::string> dq;
// Assign elements using count and value
dq.assign(3, "Hello");
std::cout << "Deque after assign with count and value: ";
for (const auto& elem : dq) {
std::cout << elem << " "; // Output: Hello Hello Hello
}
std::cout << "\n";
// Assign elements from a range (initializer list)
dq.assign({"Welcome", "to", "C++", "Programming"});
std::cout << "Deque after assign with initializer list: ";
for (const auto& elem : dq) {
std::cout << elem << " "; // Output: Welcome to C++ Programming
}
std::cout << "\n";
// Example: Using `deque::at`
try {
std::cout << "Element at index 1: " << dq.at(1) << "\n"; // Output: to
// Modify an element using `at()`
dq.at(2) = "Modern";
std::cout << "Deque after modifying element at index 2: ";
for (const auto& elem : dq) {
std::cout << elem << " "; // Output: Welcome to Modern Programming
}
std::cout << "\n";
// Access out-of-bounds index to trigger exception
std::cout << "Accessing out-of-bounds index: " << dq.at(10) << "\n";
} catch (const std::out_of_range& e) {
std::cout << "Exception: " << e.what() << "\n"; // Handles out-of-bounds error
}
return 0;
}
Output:
Deque after assign with count and value: Hello Hello Hello
Deque after assign with initializer list: Welcome to C++ Programming
Element at index 1: to
Deque after modifying element at index 2: Welcome to Modern Programming
Accessing out-of-bounds index: Exception: deque::_M_range_check: __n (which is 10)>= this->size() (which is 4)
Explanation:
- The first assign call creates three items with the value "Hello".
- The second assign replaces the entire deque content with a set of strings from an initializer list.
- Reaches certain components at valid indices and modifies them.
- Throws an exception for invalid index access to guarantee security.
Example 3:
Let us take another example to illustrate the deque::assign and deque::at in C++.
#include <iostream>
#include <deque>
int main() {
// Create an empty deque
std::deque<int> dq;
// Example 1: Using `deque::assign` to initialize contents
dq.assign(4, 7); // Assign 4 elements, each with the value 7
std::cout << "Deque after assign (4 elements of value 7): ";
for (int elem : dq) {
std::cout << elem << " "; // Output: 7 7 7 7
}
std::cout << "\n";
// Replace elements with a range from an array
int arr[] = {10, 20, 30, 40, 50};
dq.assign(arr, arr + 3); // Assign first 3 elements from arr
std::cout << "Deque after assigning from array range: ";
for (int elem : dq) {
std::cout << elem << " "; // Output: 10 20 30
}
std::cout << "\n";
// Example 2: Using `deque::at` for safe access
try {
// Access and modify elements using `at()`
std::cout << "Value at index 1: " << dq.at(1) << "\n"; // Output: 20
dq.at(1) = 25; // Update the value at index 1
std::cout << "Deque after modifying index 1: ";
for (int elem : dq) {
std::cout << elem << " "; // Output: 10 25 30
}
std::cout << "\n";
// Attempt to access an invalid index
std::cout << "Accessing element at index 5: " << dq.at(5) << "\n";
} catch (const std::out_of_range& e) {
std::cout << "Exception: " << e.what() << "\n"; // Output: Exception message
}
return 0;
}
Output:
Deque after assign (4 elements of value 7): 7 7 7 7
Deque after assigning from array range: 10 20 30
Value at index 1: 20
Deque after modifying index 1: 10 25 30
Accessing element at index 5: Exception: deque::_M_range_check: __n (which is 5)>= this->size() (which is 3)
Explanation:
- Initially assigns the value 7 to 4 elements.
- After that, the deque is replaced by the array's first three entries.
- Changes an element's value at index 1 in a safe way.
- When an out-of-range index (5) is attempted to be accessed, an exception is raised.
Conclusion:
In C++, deque::at and deque::assign serve different purposes for handling and interacting with std::deque elements. Because the assign function is built for bulk operations, we can expand and replace each element in the deque by reinitializing it with new data from a range, a repeated value, or an initializer list. However, it offers safe value retrieval or modification by giving precise access to individual components with bounds checking. Safer element management is promoted by assigning an exception for out-of-bounds access and by changing the deque's complete structure while keeping it at its current size. Knowing the distinctions between them guarantees that std::deque is used as effectively as feasible for a specific use case, such reinitializing its content or securely accessing individual elements.