Pull to refresh

Comments 21

я конечно всё понимаю, но указатель это и тоже итератор

На самом деле, на сегодняшний день уже вообще нет особого смысла использовать голые/сырые указатели (raw pointers). 

Ну напишите без них свой аллокатор...

Вам встречались другие варианты? Возможно в художественном переводе в каких то контекстах адекватнее другие синонимы, но в технических текстах о выделении памяти альтернатив не видел.

Когда я писал на С++ (это было давно), писали просто - область памяти в хипе. И все было понятно.

Это было наверное ну ОЧЕНЬ давно. Начал учить плюсы году в 2011-м. Везде и всегда писали "куча" и уже точно никто и нигде не употреблял англицизмы в тексте) В речи да, до сих пор говорят "в хипе", но в текстах уже 100500 лет пишут "куча".

писали просто - область памяти в хипе

В печатных книжках?

Упоминание контейнеров STL также не спроста — итераторы нельзя использовать с C-массивами.

А вот и неправда:

int foobar(int n)
{
    int a[] = {1, 2, 3, 5, 9};
    auto it = std::find(std::begin(a), std::end(a), n);
    if(it != std::end(a))
        return std::distance(std::begin(a), it);
    return -1;
}

это же по сути обертка над сырым указателем. сами по себе C-style массивы не умеют так делать, просто конструктор итератора позволяет сделать итератор из указателя

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

это же по сути обертка над сырым указателем

Так и в std::array итератор - тоже обёртка над сырым указателем. Они вообще между собой ничем не отличаются, даже типом:

    int a[] = {1, 2, 3};
    std::array<int, 3> b = {1, 2, 3};
    auto it1 = std::begin(a);
    auto it2 = std::begin(b);
    std::cout << typeid(it1).name() << std::endl;
    std::cout << typeid(it2).name() << std::endl;

Выведет для g++ и clang++:

Pi
Pi

Т.е. указатели на int, в данном случае.

сами по себе C-style массивы не умеют так делать

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

Там для таких случаев придумали contiguous итератор, но в реализации я как-то его не видел)

На самом деле, на сегодняшний день уже вообще нет особого смысла использовать голые/сырые указатели (raw pointers).

Core Guidelines с вами не согласен.

Passing a smart pointer transfers or shares ownership and should only be used when ownership semantics are intended. A function that does not manipulate lifetime should take raw pointers or references instead

Вообще, я бы вам рекомендовал не пытаться изобретать велосипеды, а потратить силы на перевод того, что уже хорошо написано и неплохо обосновано, от этого будет больше пользы.

Учитывая, что указатель всегда хранит адрес памяти, его всегда можно преобразовать в целое число (которое и является адресом).

Штош :) Рекомендую вам ознакомиться с интересной статьёй на тему указателей на методы класса)

Pointers to member functions are very strange animals

Ну или хотя бы заглянуть в этот топик на Stackoverflow. Вас ждёт сюрприз :)

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

С++ - это про оптимизацию.

С подходом, описанным в этой статье, надо писать на Java. Да, современные компиляторы часто справляются превратить смартпоинтеры в указатели обратно, или контейнеры в С массивы (которые при обходе быстрее). Но чтобы кмпилятор это мог сделать надо ему помогать. А высказывания в духе "не пользуйтесь сырыми указателями / С массивами никогда" вызывает вопрос: а зачем тогда пользоваться крестами?

Правило #1 в плюсах - zero abstraction cost. Собственно из-за него многое в плюсах ТАК неудобно. Поэтому в подавляющем большинстве случаев совет, в целом, верный и пользование unique_ptr будет бесплатным.

С shared_ptr сложнее, но этот указатель и не нужен практически никогда, а если нужен, нужно четырежды поднимать "а точно ли нужен?".

Для замены С-массивам давно есть std::array, который в сочетании с CTAD из С++17 вроде даже удобно использовать (не обязательно вручную задавать размерность).

И всё это в целом-то бесплатно. Так что ничего ужасного в совете как таковом нет. А вот в подаче да, проблема есть. В статье делается несколько ультимативных заявлений, без внятного объяснения, и, что хуже всего, без хороших примеров и рассмотрения крайних случаев. Что сильно снижает ценность статьи.

Я могу согласиться с формулировкой "если можно обойтись без указателей - не используйте". Но то, что они сейчас вообще не нужны - это перебор, в низкоуровневых библиотеках и системном софте явные указатели (с явной арифметикой, кастингом на целые и т.п.) часто необходимы.

Допустим у нас есть карта - двумерный массив и некий агент. Мы хотим проитерировать клетки перед агентом. Но в зависимости от направления итерировать надо или по x или по y. В голову приходит примерно такой подход:

...
int i, xi, yi;
...
  
switch (direction)
  {
    case 0:
      xi = x + 1;
      yi = y - 1;
      iter = &yi;
    case 1:
      xi = x - 1;
      yi = y + 1;
      iter = &xi;
    ....
  }

for (i = 0; i < 4; i++)
  {
    scan(cell[xi][yi]);
    (*iter)++;
  }

Как грамотно решать эту задачу на современном C++ ?

Вспомнилась статья "Что должен знать каждый программист о памяти". Там тоже был обход массива)

Sign up to leave a comment.