Только что подумала, что пустую лямбду достаточно удобно набирать, так как клавиши расположены рядом и даже Shift надо один раз удерживать:
Чтоб пост не был таким коротким, пример подсчета числа элементов, удовлетворящих предикату:
[](){}Чтоб пост не был таким коротким, пример подсчета числа элементов, удовлетворящих предикату:
std::vector<std::string> v = {"abc", "a", "ab", "c", "sd", "sjc"};
std::cout << std::count_if(v.begin(), v.end(),
[](const std::string &str)
{ return str.size() == 3; }); // 2Допустим у нас имеется некая функция, скажем isClose с двумя параметрами, и нам нужно использовать ее для некоего алгоритма, скажем find_if, который ожидает вызываемый объект с одним параметром. Альтернативой лямбде может стать использование std::bind:
bind получает вызываемый объект и создает новый вызываемый объект, адаптируя список параметров исходного. В данном случае, создастся isCloseToOne, который будет вызывать isClose, прокидывая первый аргумент (placeholders::_1) в isClose, а вторым аргументом будет скопированное значение maxDistance.
#include <functional>
size_t distance(const std::string& str1, const std::string& str2)
{
// TODO: Левенштейн
return str1.size() - str2.size();
}
bool isClose(const std::string& str1, size_t n)
{
return distance(str1, "ATGA") <= n;
}
int main()
{
size_t maxDistance = 1;
auto isCloseToOne = std::bind(isClose, std::placeholders::_1, maxDistance);
maxDistance = -1; // не влияет на копию
std::cout << isCloseToOne("CACAC") << std::endl; // 1
std::vector<std::string> v = { "ACGTTA", "GTTA", "CCATAT" };
auto it = std::find_if(
v.cbegin(), v.cend(),
// isClose); // ошибка: too few arguments
isCloseToOne); // один аргумент
if (it != v.cend()) std::cout << *it; // GTTA
return 0;
}
bind получает вызываемый объект и создает новый вызываемый объект, адаптируя список параметров исходного. В данном случае, создастся isCloseToOne, который будет вызывать isClose, прокидывая первый аргумент (placeholders::_1) в isClose, а вторым аргументом будет скопированное значение maxDistance.
❤3👍1
std::bind можно использовать для перестановки аргументов. Допустим, мы имеем некую функцию func с шестью аргументами. Сделаем новый вызываемый объект, так что его первый аргумент _1 станет пятым, а второй _2 первым и шестым:
Вызовы func2 и func приведут к одинаковым результатам. Знакоместа _1 и _2 займут указанные позиции в func. Как видим, мы можем менять не только порядок, но и повторять аргументы.
#include <functional>
void func(
const std::string& s1, // 1 => _2
int i, // 2
float f, // 3
double d, // 4
char c, // 5 => _1
const std::string& s2) // 6 => _2
{
std::cout << s1 << i << f << d << c << s2 << std::endl;
}
int main()
{
using namespace std::placeholders;
auto func2 = std::bind(func, _2, 1, 2.0f, 3.0, _1, _2);
func2('a', "___"); // ___123a___
func("___", 1, 2.0f, 3.0, 'a', "___"); // ___123a___
return 0;
}
Вызовы func2 и func приведут к одинаковым результатам. Знакоместа _1 и _2 займут указанные позиции в func. Как видим, мы можем менять не только порядок, но и повторять аргументы.
👍3🤯3❤1
std::string::find возврашает позицию найденной подстроки. Если такой строки нет, то вернется std::string::npos, что видимо означает "no pos".
Причина, по которой это поле не назвали nopos, дабы повысить читаемость за счет +1 символа, далека от моего понимания.
Интересно, что беззнаковому npos присваивается знаковое -1:
Такой каст приводит к получению максимального значения для этого типа. На x86-64 у меня получилось 18446744073709551615. Давайте проверим:
Раз так можно в std, то можно и нам пихать -1 в size_t 😁
#cpp #string
Причина, по которой это поле не назвали nopos, дабы повысить читаемость за счет +1 символа, далека от моего понимания.
Интересно, что беззнаковому npos присваивается знаковое -1:
cpp static constexpr auto npos{static_cast<size_type>(-1)};Такой каст приводит к получению максимального значения для этого типа. На x86-64 у меня получилось 18446744073709551615. Давайте проверим:
#include <iostream>
#include <string>
int main()
{
std::string str("abc");
auto pos = str.find("c");
if (pos != str.npos) {
std::cout << "found at: " << pos << std::endl;
}
std::cout << std::numeric_limits<std::string::size_type>::max() << std::endl; // 18446744073709551615
std::cout << std::string::npos << std::endl; // 18446744073709551615
std::cout << static_cast<size_t>(-1) << std::endl; // 18446744073709551615
return 0;
}
Раз так можно в std, то можно и нам пихать -1 в size_t 😁
#cpp #string
🔥2
Добью тему std::bind для закрепления. В примере ниже сортируем вектор строк по длине (кажется, сортировка не стабильная). А затем переиспользуем функцию isShorter, переставив параметры местами с помощью bind, так что у нас получается "обратная" сортировка - по убыванию длины.
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <algorithm>
bool isShorter(const std::string& str1, const std::string& str2)
{
return str1.size() < str2.size();
}
int main()
{
std::vector<std::string> v = { "ACGTTAC", "GTTA", "CCATAT" };
std::sort(v.begin(), v.end(), isShorter);
for (const auto& str : v) {
std::cout << str << " "; // GTTA CCATAT ACGTTAC
}
std::cout << std::endl;
std::sort(v.begin(), v.end(),
std::bind(isShorter, std::placeholders::_2, std::placeholders::_1));
for (const auto& str : v) {
std::cout << str << " "; // ACGTTAC CCATAT GTTA
}
return 0;
}
🔥2🏆1
Встроенные пространства имен (inline namespace) неявно вызывают директиву using для вложенных неймспейсов. Когда осуществляется поиск имени, члены встроенного пространства используются вперед, даже если такое имя уже объявлено.
В примере ниже, если скомпилировать с USE_INLINE_B, то выведется 1, иначе 2:
Inline namespaces обычно используются для версионности, например в библиотеках (ABI).
Еще пример, в котором доступны outer::inner::foo() и outer::foo():
В примере ниже, если скомпилировать с USE_INLINE_B, то выведется 1, иначе 2:
namespace A {
#if USE_INLINE_B
inline
#endif
namespace B {
int foo(bool) { return 1; }
}
int foo(int) { return 2; }
}
int main(void) {
return A::foo(true);
}Inline namespaces обычно используются для версионности, например в библиотеках (ABI).
Еще пример, в котором доступны outer::inner::foo() и outer::foo():
namespace outer {
inline namespace inner {
void foo();
} // namespace inner
} // namespace outer👍4
Увидела на реддит список (довольно базовых?) вопросов с одного собеседования на C++ разработчика. Может кому-то будет полезно/интересно.
Основы C++:
* Разница между ссылкой и указателем?
* Разница между выделением памяти на куче и стеке?
* Какие типы умных указателей существуют?
* Как реализован unique_ptr? Как сделать, чтоб у объекта был только один владелец?
* Как работает shared_ptr ? Как синхронизируется подсчет ссылок?
* Как можно скопировать unique_ptr или передать от одного объекта другому?
* Что такое rvalue и lvalue?
* Что такое std::move и std::forward() ?
ООП:
* Способы получить доступ к приватным полям некоторого класса?
* Может ли класс наследовать множество классов?
* Инициализируются ли статические поля в конструкторе класса?
* Может ли исключение быть выброшенным в конструкторе/деструкторе? Как это предотвратить?
* Что такое виртуальный метод?
* Зачем нужен виртуальный деструктор?
* Разница между абстрактным классом и интерфейсом?
* Может ли конструктор быть виртуальным?
* Как ключевое слово const используется для методов класса?
* Как защитить объект от копирования?
STL контейнеры:
* Разница между vector и list?
* Разница между map и unordered_map?
* Когда вызов push_back() инвалидирует итератор vector?
* Как изменить свой класс, чтоб использовать с map/unordered_map?
Потоки:
* Разница между процессом и потоком?
* Может ли поток быть запущен дважды?
* Способы синхронизации потоков?
* Что такое дедлок?
#cpp #собеседования
Основы C++:
* Разница между ссылкой и указателем?
* Разница между выделением памяти на куче и стеке?
* Какие типы умных указателей существуют?
* Как реализован unique_ptr? Как сделать, чтоб у объекта был только один владелец?
* Как работает shared_ptr ? Как синхронизируется подсчет ссылок?
* Как можно скопировать unique_ptr или передать от одного объекта другому?
* Что такое rvalue и lvalue?
* Что такое std::move и std::forward() ?
ООП:
* Способы получить доступ к приватным полям некоторого класса?
* Может ли класс наследовать множество классов?
* Инициализируются ли статические поля в конструкторе класса?
* Может ли исключение быть выброшенным в конструкторе/деструкторе? Как это предотвратить?
* Что такое виртуальный метод?
* Зачем нужен виртуальный деструктор?
* Разница между абстрактным классом и интерфейсом?
* Может ли конструктор быть виртуальным?
* Как ключевое слово const используется для методов класса?
* Как защитить объект от копирования?
STL контейнеры:
* Разница между vector и list?
* Разница между map и unordered_map?
* Когда вызов push_back() инвалидирует итератор vector?
* Как изменить свой класс, чтоб использовать с map/unordered_map?
Потоки:
* Разница между процессом и потоком?
* Может ли поток быть запущен дважды?
* Способы синхронизации потоков?
* Что такое дедлок?
#cpp #собеседования
👍7
Адаптер вставки - адаптер итератора, получающий контейнер и возвращающий итератор, позволяющий вставлять элементы в указанный контейнер.
Адаптер back_inserter создает итератор, использующий функцию push_back, тогда как front_inserter использует push_front. Пример:
Адаптер back_inserter создает итератор, использующий функцию push_back, тогда как front_inserter использует push_front. Пример:
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5 };
std::list<int> list1, list2;
copy(v.cbegin(), v.cend(), std::front_inserter(list1));
copy(v.cbegin(), v.cend(), std::back_inserter(list2));
for (auto i : list1)
std::cout << i << " "; // 5 4 3 2 1
std::cout << std::endl;
for (auto i : list2)
std::cout << i << " "; // 1 2 3 4 5
return 0;
}
👍4
Время жизни объектов в C++ можно разделить на 4 категории:
1. Статическое время жизни
Все время работы приложения, выделяются в начале запуска и освобождаются при завершении. Сюда входят глобальные переменные, статические члены, статические локальные переменные.
2. Потоковое время жизни
Объекты существуют в течение жизни потока, к которому они принадлежат. Создаются при запуске потока и разрушаются при выходе потока. Указываются ключевым словом thread_local:
3. Автоматическое время жизни
Создаются в момент определения и разрушаются при выходе из области видимости. Более известны как локальные объекты/объекты на стеке. Например локальные нестатические переменные и параметры функции.
4. Динамическое время жизни
Создаются в рантайме с использованием функци выделения памяти как new, malloc и тп. Временем жизни таких объектов нужно управлять вручную.
1. Статическое время жизни
Все время работы приложения, выделяются в начале запуска и освобождаются при завершении. Сюда входят глобальные переменные, статические члены, статические локальные переменные.
2. Потоковое время жизни
Объекты существуют в течение жизни потока, к которому они принадлежат. Создаются при запуске потока и разрушаются при выходе потока. Указываются ключевым словом thread_local:
thread_local int my_var; // Thread storage duration
3. Автоматическое время жизни
Создаются в момент определения и разрушаются при выходе из области видимости. Более известны как локальные объекты/объекты на стеке. Например локальные нестатические переменные и параметры функции.
4. Динамическое время жизни
Создаются в рантайме с использованием функци выделения памяти как new, malloc и тп. Временем жизни таких объектов нужно управлять вручную.
👍1👏1
Не моя вина, но сегодня у меня день рожденюшко. Сделоть подарок можно денюжным переводом (н-р через TG Wallet).
TON: UQCinAVCbNfOxvOfsyBjtmKrZoQr6t1tQ5A-XLS3XwJanTwr
USDT: TCyFuko2mxtduRc9SgPkZtPWUk7cPz3vZt
BTC:
1Ce8eJmJNDUxHdnqQGfgBVkLzixSBhEsaC
TON: UQCinAVCbNfOxvOfsyBjtmKrZoQr6t1tQ5A-XLS3XwJanTwr
USDT: TCyFuko2mxtduRc9SgPkZtPWUk7cPz3vZt
BTC:
1Ce8eJmJNDUxHdnqQGfgBVkLzixSBhEsaC
🎉6
Давайте рассмотрим на первый раз простую задачу - итерирование вектора в обратном порядке, то есть от конца к началу. Для начала возьмем просто индекс:
Вроде бы все хорошо, но на моей машине в int максимум поместится 2147483647, тогда как в size_type вектора (обычно size_t) уже 18446744073709551615.
Давайте исправим ситуацию и возьмем size_t в качестве индекса:
А есть ли способ лучше, через итераторы? Да - реверсивный итератор перебирает контейнер с конца в начало. Для этого доступны rbegin/rend:
Хочу отметить, что здесь нет ошибки и реверсивный итератор действительно инкрементируется, то есть продвигается наоборот. Почему, расскажу в другой раз😉.
std::vector<int> v = {1,2,3,4,5};
const std::vector<int>::size_type size = v.size();
int i;
for (i = size - 1; i != -1; --i) {
std::cout << v[i]; // 54321
}
std::cout << std::endl << i << std::endl; // -1Вроде бы все хорошо, но на моей машине в int максимум поместится 2147483647, тогда как в size_type вектора (обычно size_t) уже 18446744073709551615.
Давайте исправим ситуацию и возьмем size_t в качестве индекса:
size_t j;
for (j = size - 1; j != -1; --j) {
std::cout << v[j]; // 54321
}
std::cout << std::endl << j << std::endl; // 18446744073709551615
А есть ли способ лучше, через итераторы? Да - реверсивный итератор перебирает контейнер с конца в начало. Для этого доступны rbegin/rend:
for (auto it = v.rbegin(); it != v.rend(); ++it) {
std::cout << *it;
}Хочу отметить, что здесь нет ошибки и реверсивный итератор действительно инкрементируется, то есть продвигается наоборот. Почему, расскажу в другой раз😉.
Так как реверсивный итератор перебирает контейнер от последнего элемента к первому, то смысл инкремента инвертирован:
Для получения реверсивного итератора существуют rbegin()/rend(), а также константные аналоги crbegin()/crend(). rbegin указывает на последний элемент контейнера, а rend на элемент перед контейнером, аналогично обычным итераторам, просто наоборот. Изображение пояснит соотношение на векторе.
Возможно, вам покажется неправильным, что ++it идет на предыдущий элемент, но это позволяет использовать все стандартные алгоритмы задом наперед. Например, отсортируем вектор в порядке убывания:
++it переводит итератор на предыдущий элемент, а --it на следующий.Для получения реверсивного итератора существуют rbegin()/rend(), а также константные аналоги crbegin()/crend(). rbegin указывает на последний элемент контейнера, а rend на элемент перед контейнером, аналогично обычным итераторам, просто наоборот. Изображение пояснит соотношение на векторе.
Возможно, вам покажется неправильным, что ++it идет на предыдущий элемент, но это позволяет использовать все стандартные алгоритмы задом наперед. Например, отсортируем вектор в порядке убывания:
std::sort(v.rbegin(), v.rend())👍4
Заканчиваем с реверсивными итераторами. Допустим, что нам нужно найти первое и последнее слово в строке. С первым всё понятно, используем std::find с начала:
Для поиска с конца ищем реверсивно с конца по начало, итератор правильно находится на 8-й позиции, но при получении подстроки слово будет задом наперед:
Почему? Потому что итератор идет в обратном направлении. Для перехода на прямое направление используем вызов base() у реверсивного итератора:
Обратите внимание, что в паре с base() идет обычный итератор.
std::string str = "One Two Three";
auto space = std::find(str.cbegin(), str.cend(), ' ');
std::cout
<< std::string(str.cbegin(), space) // One
<< std::endl;
Для поиска с конца ищем реверсивно с конца по начало, итератор правильно находится на 8-й позиции, но при получении подстроки слово будет задом наперед:
auto rspace = std::find(str.crbegin(), str.crend(), ' ');
std::cout
<< str.crend() - rspace // at 8, correct
<< std::endl;
std::cout
<< std::string(str.crbegin(), rspace) // eerhT
<< std::endl;
Почему? Потому что итератор идет в обратном направлении. Для перехода на прямое направление используем вызов base() у реверсивного итератора:
std::cout
<< std::string(rspace.base(), str.cend()) // Three
<< std::endl;
Обратите внимание, что в паре с base() идет обычный итератор.
❤1👍1
Боян, но все равно смешно)
https://stackoverflow.com/questions/1642028/what-is-the-operator-in-c-c?rq=2
#stackoverflow #юмор
https://stackoverflow.com/questions/1642028/what-is-the-operator-in-c-c?rq=2
#stackoverflow #юмор
Stack Overflow
What is the '-->' operator in C/C++?
After reading Hidden Features and Dark Corners of C++/STL on comp.lang.c++.moderated, I was completely surprised that the following snippet compiled and worked in both Visual Studio 2008 and G++ 4....
😁7
std::list определяет несколько алгоритмов в качестве членов, например sort(), merge(), reverse(), unique(). Обобщенная версия std::sort (та, которая принимает итераторы) требует итераторы произвольного доступа, которых нет в list, поэтому std::sort нельзя использовать с list. Вместо этого следует вызывать член sort() у самого list.
Давайте ради интереса проверим скорость сортировки вектора и списка из 100 тысяч int-ов:
На MSVC на моей тачке (x86_64) получилось, что сортировка списка в 1.8 раза медленней сортировки вектора (если я нигде не обосралась). А почему так, думаю догадаются многие 😁.
Давайте ради интереса проверим скорость сортировки вектора и списка из 100 тысяч int-ов:
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <chrono>
constexpr int sortSize = 100'000;
int main()
{
std::list<int> list;
for (int i = sortSize; i > 0 ; --i) {
list.push_back(i);
}
auto begin1 = std::chrono::steady_clock::now();
//std::sort(list.begin(), list.end()); // не скомпилится
list.sort(); // скомпилится
auto end1 = std::chrono::steady_clock::now();
std::vector<int> vector;
vector.resize(sortSize);
for (int i = sortSize; i > 0; --i) {
vector[sortSize - i] = i;
}
auto begin2 = std::chrono::steady_clock::now();
std::sort(vector.begin(), vector.end());
auto end2 = std::chrono::steady_clock::now();
auto it_l = list.begin();
for (size_t i = 0; i < 10; ++i) {
std::cout << *it_l++ << " "; // 1 2 3 4 5 6 7 8 9 10
}
std::cout << std::endl;
auto it_v = vector.begin();
for (size_t i = 0; i < 10; ++i) {
std::cout << *it_v++ << " "; // 1 2 3 4 5 6 7 8 9 10
}
std::cout << std::endl;
std::cout << "list: "
<< std::chrono::duration_cast<std::chrono::microseconds>(end1 - begin1).count()
<< " mcs"
<< std::endl;
std::cout << "vector: "
<< std::chrono::duration_cast<std::chrono::microseconds>(end2 - begin2).count()
<< " mcs"
<< std::endl;
// list: 1717 mcs
// vector : 958 mcs
return 0;
}
На MSVC на моей тачке (x86_64) получилось, что сортировка списка в 1.8 раза медленней сортировки вектора (если я нигде не обосралась). А почему так, думаю догадаются многие 😁.
Начиная с C++17 if может быть с инициализатором`if (init; condition)` (подобно for). Переменная доступна только внутри if :
Во втором примере показано, что переменная также доступна в else.
#cpp17
#include <iostream>
#include <cstdlib>
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
// C++17 if statement with initializer
// if (init; condition) {
if (auto it = std::find(v.begin(), v.end(), 5); it != v.end()) {
std::cout << *it << std::endl;
}
srand(time(NULL));
if (int random = rand(); random % 2 == 0) {
std::cout << random << " is an even number" << std::endl;
} else {
std::cout << random << " is an odd number" << std::endl;
}
return 0;
}
Во втором примере показано, что переменная также доступна в else.
#cpp17
👍5🤔1
Классический пример использования ассоциативного контейнера std::map - подсчет числа слов в строке.
Для ассоциативного контейнера нужно задать типы ключа (строка - слово) и значения (число слов).
Вызов
При итерации по словарю будет возвращен std::pair, гдe first - это ключ, а second - значение.
#include <iostream>
#include <map>
#include <string>
#include <sstream>
#include <iomanip>
int main()
{
std::string str =
"the only person with whom you have to"
" compare yourself is you in the past";
std::stringstream stream(str);
// счетчик числа слов: string - ключ, size_t - значение
std::map<std::string, size_t> wordCount;
std::string word;
while (stream >> word) { // разделяем слова по пробелам
++wordCount[word]; // добавляем слово или берем уже сущ.
}
std::cout << wordCount["the"] << std::endl; // 2
for (auto w : wordCount) { // w - pair
std::cout << std::setw(10) << w.first << ": "
<< w.second << std::endl;
}
// with: 1
// you: 2
// ...
return 0;
}
Для ассоциативного контейнера нужно задать типы ключа (строка - слово) и значения (число слов).
Вызов
wordCount[word] добавит слово в мапу со значением 0, если такого слова нет.++wordCount[word] увеличит значение в мапе на 1.wordCount["the"] вернет количество the.При итерации по словарю будет возвращен std::pair, гдe first - это ключ, а second - значение.
👍1
На собеседованиях по алгоритмам часто спрашивают, как обратить список. Ответ: вызывать метод reverse() 😆
#юмор
#include <iostream>
#include <list>
int main()
{
std::list<int> l;
for (int i = 0; i < 5; ++i) l.push_back(i);
// 0 1 2 3 4
for (int i : l) std::cout << i << " ";
std::cout << std::endl;
l.reverse();
// 4 3 2 1 0
for (int i : l) std::cout << i << " ";
std::cout << std::endl;
return 0;
}
#юмор
А давайте теперь сравним время работы (MSVC 64 bit) обобщенной версии remove_if и встроенной в std::list на примере удаления всех четных элементов из списка на 100 тысяч int-ов:
Обобщенный в 2 раза быстрее, что?😱
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <chrono>
int main()
{
std::list<int> list;
for (int i = 0; i < 100'000; ++i) {
list.push_back(i);
}
// сделаем копии
std::list<int> list_copy1 = list;
std::list<int> list_copy2 = list;
auto begin1 = std::chrono::steady_clock::now();
std::remove_if(
list_copy1.begin(),
list_copy1.end(),
[](int n) { return n % 2 == 0; });
auto end1 = std::chrono::steady_clock::now();
auto begin2 = std::chrono::steady_clock::now();
list_copy2.remove_if([](int n) { return n % 2 == 0; });
auto end2 = std::chrono::steady_clock::now();
auto it1 = list_copy1.begin();
for (size_t i = 0; i < 10; ++i) {
std::cout << *it1++ << " "; // 1 3 5 7 9 11 13 15 17 19
}
std::cout << std::endl;
auto it2 = list_copy2.begin();
for (size_t i = 0; i < 10; ++i) {
std::cout << *it2++ << " "; // 1 3 5 7 9 11 13 15 17 19
}
std::cout << std::endl;
std::cout << "1: "
<< std::chrono::duration_cast<std::chrono::microseconds>(end1 - begin1).count()
<< " mcs"
<< std::endl;
std::cout << "2: "
<< std::chrono::duration_cast<std::chrono::microseconds>(end2 - begin2).count()
<< " mcs"
<< std::endl;
// 1: 710 mcs
// 2: 1631 mcs
return 0;
}
Обобщенный в 2 раза быстрее, что?😱