
- Главная
- Каталог
- Интернет технологии
- C/C++ | Вопросы собесов
C/C++ | Вопросы собесов
Разбираем вопросы с собеседований на С/С++ разработчика
Статистика канала
|). Эта операция позволяет установить конкретный бит в 1, не изменяя остальные биты числа.
🚩Как это работает
Операция ИЛИ (|) сравнивает каждый бит двух чисел. Если хотя бы один из битов в соответствующей позиции равен 1, результат в этой позиции будет 1. Иначе, результат будет 0.
🚩Шаги
1⃣Создаём маску, которая имеет единицу в позиции n и нули в остальных позициях. Это можно сделать с помощью выражения 1 << n.
2⃣Применяем операцию ИЛИ между числом x и маской.
#include <iostream>
int main() {
int x = 0b00001010; // Число, с которым работаем (10 в десятичной системе)
int n = 3; // Позиция бита, которую хотим установить (начиная с 0)
// Создаём маску с единицей в позиции n
int mask = 1 << n;
// Устанавливаем бит в позиции n
x = x | mask;
// Вывод результата
std::cout << "Результат: " << std::bitset<8>(x) << std::endl; // Двоичный вывод
std::cout << "Результат: " << x << std::endl; // Десятичный вывод
return 0;
}{}
1 << n создает маску, сдвигая 1 влево на n позиций. Например, если n = 3, результат будет 0b00001000. Операция x | mask устанавливает бит в x на позиции n в 1. Если бит в x на позиции n уже был 1, он останется 1, если он был 0, то станет 1.
🚩Пример вывода
Если x было 0b00001010 и n = 3, результат будет:
Маска: 0b00001000
x | mask: 0b00001010 | 0b00001000 = 0b00001010
В результате бит в позиции 3 установлен в 1, и итоговое значение числа в двоичном формате 0b00001010 (десятичное 10).
Ставь 👍 и забирай 📚 Базу знанийdelete nullptr безопасен и не делает ничего. Стандарт гарантирует, что delete не вызывает ошибок при передаче nullptr.
int* p = nullptr;
delete p; // НИЧЕГО НЕ ПРОИЗОЙДЁТ (без ошибки){}
🚩Почему `delete nullptr` не вызывает ошибку?
Стандарт C++ (C++98, C++11, C++17, C++20) говорит:
> Если переданный в delete указатель равен nullptr, то delete ничего не делает.
Это сделано, чтобы избежать избыточных проверок в коде:
if (ptr) { // Проверка не нужна
delete ptr;
}{}
🚩Как работает `delete` внутри?
Когда вызывается delete p, компилятор:
Проверяет, равен ли p nullptr. Если да → ничего не делает.
Вызывает деструктор объекта, если p не nullptr.
Освобождает память с помощью operator delete().
🚩Что с `delete[]`?
Тоже безопасно
int* arr = nullptr;
delete[] arr; // НИЧЕГО НЕ ПРОИЗОЙДЁТ{}
🚩Ошибки, которых `delete nullptr` помогает избежать
Безопасно
void destroy(int* p) {
delete p; // Даже если p == nullptr, ошибки не будет
}{}
Опасность: двойное удаление
Хотя delete nullptr безопасен, удаление уже освобождённого указателя — ошибка!
int* p = new int(10);
delete p; // Освободили память
delete p; // ❌ НЕСКОЛЬКО DELETE - неопределённое поведение (UB)!{}
Решение: после delete занулять указатель
int* p = new int(10);
delete p;
p = nullptr; // Теперь повторный delete безопасен
delete p; // ОК, ничего не делает{}
Ставь 👍 и забирай 📚 Базу знанийstd::unique_ptr и std::shared_ptr по умолчанию вызывают delete, но иногда это поведение нужно изменить.
🚩Когда нужны делиторы?
🟠Для работы с нестандартными ресурсами (не `new`)
Например, если объект создан через malloc(), fopen(), CreateFile(), то delete не подходит!
🟠Если нужно логировать или выполнять доп. действия при удалении
Можно добавить std::cout, логику очистки, сброс ресурсов.
🟠Если объект хранится в массиве (`new[]`)
delete не удалит массив корректно, нужно delete[].
🟠Если ресурс должен освобождаться особым способом
Например, в std::shared_ptr можно передать free(), fclose() или CloseHandle().
🚩Как передавать делитор в `std::unique_ptr`?
Пример: освобождение памяти от malloc() через std::free()
#include <iostream>
#include <memory>
int main() {
std::unique_ptr<int, void(*)(void*)> ptr(malloc(sizeof(int)), free);
*reinterpret_cast<int*>(ptr.get()) = 42;
std::cout << "Значение: " << *reinterpret_cast<int*>(ptr.get()) << "\n";
}{}
Здесь free используется вместо delete, потому что память выделена malloc().
Пример: закрытие файла через std::fclose()
#include <iostream>
#include <memory>
#include <cstdio>
int main() {
std::unique_ptr<FILE, decltype(&std::fclose)> file(fopen("test.txt", "w"), &std::fclose);
if (file) {
std::fprintf(file.get(), "Hello, world!\n");
}
} // `fclose(file)` вызовется автоматически!{}
🚩Как передавать делитор в `std::shared_ptr`?
В std::shared_ptr можно передавать делитор прямо в конструкторе
#include <iostream>
#include <memory>
void customDeleter(int* ptr) {
std::cout << "Удаляю объект: " << *ptr << "\n";
delete ptr;
}
int main() {
std::shared_ptr<int> ptr(new int(100), customDeleter);
} // В конце `customDeleter(ptr)` вызовется автоматически!{}
🚩Делитор для массивов (`delete[]`)
По умолчанию std::unique_ptr<int[]> сам вызывает delete[], но если std::unique_ptr<int> используется неправильно, то delete удалит только первый элемент массива!
Ошибка: delete вместо delete[]
std::unique_ptr<int> arr(new int[10]); // ОШИБКА! `delete` вызовет утечку памяти!{}
Правильный вариант
std::unique_ptr<int[], std::default_delete<int[]>> arr(new int[10]);{}
Ставь 👍 и забирай 📚 Базу знанийstd::vector, которые могут привести к множественному копированию элементов. Рассмотрим основные из них.
🟠Изменение размера (`resize`)
Метод resize() может вызвать множественное копирование, если новый размер вектора превышает его текущую вместимость (capacity).
#include <iostream>
#include <vector>
struct Data {
int value;
Data(int v) : value(v) {}
Data(const Data& other) { // Конструктор копирования
value = other.value;
std::cout << "Copying Data: " << value << std::endl;
}
};
int main() {
std::vector<Data> vec(3, Data(10)); // Заполняем 3 элементами
std::cout << "Resizing..." << std::endl;
vec.resize(10, Data(20)); // Вектор расширяется, возможны копирования
}{}
🟠Вставка элемента (`insert` и `emplace`)
Если std::vector не имеет достаточного запаса (capacity), вставка нового элемента может привести к реаллокации и копированию всех элементов.
std::vector<int> vec = {1, 2, 3};
vec.insert(vec.begin(), 0); // Вставка в начало → все элементы сдвигаются{}
🟠Присваивание (`operator=`)
Если один std::vector присваивается другому, все элементы копируются.
std::vector<int> vec1 = {1, 2, 3, 4, 5};
std::vector<int> vec2;
vec2 = vec1; // Копирование всех элементов{}
🟠Возвращение `std::vector` из функции
Если возвращаем std::vector по значению, может произойти копирование (если не работает оптимизация RVO/NRVO или перемещение).
std::vector<int> createVector() {
std::vector<int> vec(100, 42);
return vec; // Может скопироваться, если нет RVO
}{}
Ставь 👍 и забирай 📚 Базу знанийfor, который позволяет перебирать элементы контейнера (std::vector, std::array, std::map, std::set и т. д.) без индексов и итераторов.
for (auto element : container) {
// Действие с element
}{}
🚩Как это работает внутри?
Простой пример с std::vector
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
for (int x : v) { // Перебираем все элементы вектора
std::cout << x << " ";
}
}{}
Вывод
1 2 3 4 5{}
Как работает этот цикл?
Компилятор превращает его в обычный for с итератором:
for (auto it = v.begin(); it != v.end(); ++it) {
int x = *it; // Копируем элемент
std::cout << x << " ";
}{}
🚩Передача по ссылке (`&`) и по значению (`=`)
Передача по значению (=) – создаёт копию элемента
for (int x : v) { // x - копия элемента
x = 100; // НЕ изменит вектор!
}{}
Передача по ссылке (&) – изменяет оригинал
for (int& x : v) { // x - ссылка на элемент
x *= 2; // Изменит оригинальный вектор!
}{}
🚩Работает со всеми контейнерами STL
С std::map
std::map<int, std::string> m = {{1, "one"}, {2, "two"}};
for (const auto& [key, value] : m) { // structured binding (C++17)
std::cout << key << " -> " << value << "\n";
}{}
С std::set
std::set<int> s = {1, 2, 3, 4};
for (int x : s) { std::cout << x << " "; }{}
🚩Работает с `std::initializer_list`
for (int x : {10, 20, 30}) {
std::cout << x << " ";
}{}
Вывод
10 20 30{}
🚩Как работает range-based for с обычными массивами?
int arr[] = {1, 2, 3};
for (int x : arr) { std::cout << x << " "; }{}
Работает так же, как и с `std::vector`!
Работает с пользовательскими классами (если есть begin() и end())
class MyContainer {
int data[3] = {10, 20, 30};
public:
int* begin() { return data; }
int* end() { return data + 3; }
};
int main() {
MyContainer c;
for (int x : c) { std::cout << x << " "; }
}{}
Ставь 👍 и забирай 📚 Базу знанийОтзывы канала
- Добавлен: Сначала новые
- Добавлен: Сначала старые
- Оценка: По убыванию
- Оценка: По возрастанию
Каталог Телеграм-каналов для нативных размещений
C/C++ | Вопросы собесов — это Telegam канал в категории «Интернет технологии», который предлагает эффективные форматы для размещения рекламных постов в Телеграмме. Количество подписчиков канала в 4.3K и качественный контент помогают брендам привлекать внимание аудитории и увеличивать охват. Рейтинг канала составляет 5.2, количество отзывов – 1, со средней оценкой 5.0.
Вы можете запустить рекламную кампанию через сервис Telega.in, выбрав удобный формат размещения. Платформа обеспечивает прозрачные условия сотрудничества и предоставляет детальную аналитику. Стоимость размещения составляет 3636.36 ₽, а за 3 выполненных заявок канал зарекомендовал себя как надежный партнер для рекламы в TG. Размещайте интеграции уже сегодня и привлекайте новых клиентов вместе с Telega.in!
Вы снова сможете добавить каналы в корзину из каталога
Комментарий