LINUX.ORG.RU

Какую книгу по C++ выбрать?

 ,


5

2

Какую книгу по с++ выбрать

  1. Герберт Шилдт. C++ для начинающих. Шаг за шагом
  2. Стивен Прата. Язык программирования C++. Лекции и упражнения
  3. Предложите свой вариант (учил джаву, с++ смотрел видео ну можно сказать не с нуля учу)

Перемещено hobbit из general

Ответ на: комментарий от bugfixer

Покажите мне этот сегфолт. Хинт: capacity != size, нужно сильно постараться чтобы этот memwrite чужую память попортил.

Хм.

#include <iostream>
#include <vector>
#include <csignal>

int i;

void signalHandler( int signum ) {
//Обработчик SIGSEGV
   std::cerr << "Segmentation fault detected!" << std::endl;
   std::cerr <<  "i = " << i << std::endl;   
   std::exit(signum); 
}
 
int main(void)
{

    std::signal(SIGSEGV, signalHandler);
    
    std::vector<int> v = { 1, 2, 3};
    i = v[v.size()-1];
    while (i++)
    {
       v[i]=i; //Ждем когда вывалится с исключением.
    }
    return 0;
}

Запускаем:

$ g++ -o segf segf.cpp
$
$ ./segf
Segmentation fault detected!
i = 15444

Похоже за размер стека перевалило.

praseodim ★★★★★
()
Ответ на: комментарий от LamerOk

А современность С++ погоды в целом не делает в этом вопросе вообще никакой.

Делает и еще какую. Тот же auto отлично скрывает страшные имена типов итераторов, например. А auto в качестве типа возвращаемого значения позволяет возвращать типы, которые вручную бы заманался выписывать (а в случае с возвратом лямбд это вообще было бы невозможно).

C++98 уже разительно отличался от C++ с которого я начинал в 1992-м. А C++11 еще более. Чем дальше, тем больше приходится пользоваться именно концепцией итераторов, а не указателями.

Например, я вот честно ХЗ зачем здесь пример кода на C#, но попробуйте его применить к контейнеру, который хранит элементы последовательно, но не в одном непрерывном векторе, а в наборе чанков. В C++ можно сделать контейнер, который выставляет наружу итераторы и тот же std::lower_bound будет с ним работать.

Либо у нас есть задача, где алиасингом и адресной арифметикой можно получить ускорение в сотни и тысячи раз по сравнению с наивной версией с боксингом, либо нет.

Ну так давайте разберем какие-то конкретные примеры. Мне вот удалось вспомнить из последнего колупания с адресной арифметикой вот такое. Но это точно не прикладной код и делать такое приходится хорошо, если раз в год.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

я вот честно ХЗ зачем здесь пример кода на C#,

Обобщённый алгоритм в языке, где нет никакой адресной арифметики.

Ну так давайте разберем какие-то конкретные примеры.

Я выискивать из прода щас ничего не буду, возьму простейший пример даже без параметризации форматом матрицы:

struct img
{
    size_t width;
    size_t height;
    unsigned char *data; // BGR
};

extern void f(size_t x, size_t y, unsigned char r, unsigned char g, unsigned char b);

void process_bitmap(struct img &img)
{
    for(size_t y = 0; y < img.height; y++)
    {
        for(size_t x = 0; x < img.width; x++)
        {
            unsigned char *p = img.data + img.width*3*y + x*3;
            f(x, y, p[2], p[1], p[0]);
        }
    }
}

как это эффективно сделать без адресной арифметики и алиасинга?

LamerOk ★★★★★
()
Последнее исправление: LamerOk (всего исправлений: 1)
Ответ на: комментарий от LamerOk

unsigned char p = img.data + img.width3y + x3;

тут явное общее подвыражение. вы плюсуюете каждый раз img.data, вычисляете указатель на начало строки

img.data + img.width3y

эта лабуда не меняется при цикле по х. и умножение x*3 избыточно.

у настоящих посонов цикл по x должен выглядеть так:

unsigned char* p  = img.data + img.width*3*y; ///начало
unsigned char* pp = p + img.width*3; ///конец
while ( p < pp) {
  f(x, y, p[2], p[1], p[0]);
  p += 3; 
}

про оптимизацию компилятором слыхал. но не факт что он раскрутит. это надо на годболте смотреть

alysnix ★★★
()
Ответ на: комментарий от LamerOk

Обобщённый алгоритм в языке, где нет никакой адресной арифметики.

Выясняется, что он обобщенный только для типа в последовательности, но не для самой последовательности. Т.е. не такой уж и обобщенный.

как это эффективно сделать без адресной арифметики и алиасинга?

Хороший пример. Но зачем для этого знать Си и почему нельзя это разбирать сразу в C++? В Си какая-то другая адресная арифметика?

eao197 ★★★★★
()
Ответ на: комментарий от praseodim

Какого ещё стэка?

Показалось, что небольшая переменная на стеке размещена

Небольшая переменная на стэке и размещена, а вот обращения идут уже в выделенный буфер, и выделен он совсем не на стэке.

LamerOk ★★★★★
()
Ответ на: комментарий от eao197

Обобщённый алгоритм в языке, где нет никакой адресной арифметики.

Выясняется, что он обобщенный только для типа в последовательности, но не для самой последовательности. Т.е. не такой уж и обобщенный.

С чего бы? Оператор [] прекрасно переопределяется. Код из примера выше почти полная копия std::binary_search. Чтобы сделать его полной копией достаточно добавить функцию - компаратор.

Это пример того, что в этом объёме выразительные возможности C# и C++ практически идентичны. Разница между ними, конечно, есть, но уже в других деталях.

Но зачем для этого знать Си

Мы уже ушли с этого вопроса на вопрос "а зачем вообще нужна адресная арифметика?".

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

С чего бы?

А разве прототип метода не указывает прямо на тип входной последовательности?

public int FindIndex(T[] sortedData, T item)

Мы уже ушли с этого вопроса на вопрос «а зачем вообще нужна адресная арифметика?».

Может покажете место, где это произошло, потому что я не помню чтобы где-то утверждал, что адресная арифметика не нужна.

В современном C++ дело с ней приходится иметь реже, чем раньше (мне, например, в своей работе очень редко). Но под сомнение я эту часть C++ не ставил.

Я вам на другое указывал: ваш пример с ошибочным идексом в массиве не требует рассмотрения указателей, это всего лишь частный случай ошибок при работе с итераторами, т.к. запись:

v[v.size()] = 0;

полностью эквивалентна записи:

*(v.begin() + v.size()) = 0;

И в таком варианте она применима не только к std::vector, но и к другим типам, например, к std::deque.

Т.е. чтобы объяснить изучающему C++ суть проблемы в этом случае не нужно опускаться на уровень адресной арифметики.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

запись: v[v.size()] = 0; полностью эквивалентна записи: *(v.begin() + v.size()) = 0;

И в таком варианте она применима не только к std::vector, но и к другим типам

У других типов может быть другая семантика оператора []

#include <map>
void test() {
    std::map<size_t, int> list;
    auto begin{ list.begin()};
    // begin + list.size(); // ??
    list[list.size()];
}
vM ★★
()
Ответ на: комментарий от vM

Когда я писал «И в таком варианте она применима не только к std::vector, но и к другим типам», то речь шла именно о записи:

*(v.begin() + v.size()) = 0;

Кроме того, «она применима не только к std::vector, но и к другим типам» не означает, что применима ко всем другим типам.

Так что решительно непонятно что именно вы хотели сказать своим комментарием.

eao197 ★★★★★
()
Ответ на: комментарий от vM

С чего бы?

А разве прототип метода не указывает прямо на тип входной последовательности?

Ровно в той же, что мере, что и std::binary_search - обобщённая функция принимает на вход контейнер элементов шаблонного типа T и элемент шаблонного типа T, который ищет в контейнере. Шаблонный тип T должен удовлетворять интерфейс IComparable - это полный аналог наличия оператора std::less для C++, с той только разницей, что в случае ошибки вместо загадочной простыни на 1000 строк про отсутствие оператора в месте вызова тут будет выдана корректная ошибка.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

Ровно в той же, что мере, что и std::binary_search

Вы точно уверены на счет «принимает на вход контейнер»?

https://en.cppreference.com/w/cpp/algorithm/binary_search.html

Я не знаток C#, но разве запись T[] означает произвольный контейнер с наличием оператора []?

eao197 ★★★★★
()
Ответ на: комментарий от LamerOk

А что ещё она может означать?

Что-то вроде аналога C++ного span, т.е. непрерывную последовательность из N элементов.

Повторюсь, я не знаток C#, но неужели T[] – это эквивалент произвольного IEnumerable?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

неужели T[] – это эквивалент произвольного IEnumerable?

T[] - это экземпляр класса array параметризированый шаблонным типом T. Такой класс может быть создан пользователем через indexer - я же выше писал:

Оператор [] прекрасно переопределяется.

Array реализует несколько интерфейсов, среди них и IEnumerable, так что, да, одномерный T[] может быть использован везде, где используется IEnumerable.

LamerOk ★★★★★
()
Ответ на: комментарий от LamerOk

А зачем?

Я это к тому, что если бы у вас в примере было:

int FindIndex(IEnumerable<T> sortedData, T item)

То это было бы более похоже на C++ный std::binary_search. А так сравнение не равноценное.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Сишарпный IEnumerable<T> в переводе на сиплюсплюснотый язык - это прямой итератор чтения / записи без произвольного доступа. В столь любимом вами "современном С++" это комбинация трейтов input_iterator / output_iterator / forward_iterator.

А для бинарного поиска нам нужен трейт random_access_iterator, что в сишарпе предоставляется оператором [].

LamerOk ★★★★★
()
Последнее исправление: LamerOk (всего исправлений: 1)

С плюсами такая штука - читай всё, что попадётся под руку. Язык довольно разлапистый, и для нормального знакомства потребуется не одна книжка. Классики: Страуструп, Мейерс, Йосутис. Если что-то непонятно, спрашивай у chatGPT, и проверяй ответы экспериментально. И Шилда, и Прату бери, нос не вороти. Отзывы в инете читай, но учти, что люди частенько хотят идеальных книг, а такого не бывает.

seiken ★★★★★
()
Последнее исправление: seiken (всего исправлений: 1)
Ответ на: комментарий от seiken

Вот я, например, сейчас читаю классическую механику, Cambridge press, казалось бы не хухры-мухры, книга 2006г., 6я перепечатка. И там во вводной части о тройном векторном произведении, как минимум в одном месте такая чушь написана, что впору этот кэмбридж пресс использовать для розжиги печки. И это естественнонаучная дисциплина. Что же говорить о интеллектуально менее развитых «специалистах по программированию»…

seiken ★★★★★
()