Почему карта пропускает первый символ? [Дубликат]

Процедура поиска по всей базе данных:

    CREATE or REPLACE PROCEDURE SEARCH_DB(SEARCH_STR IN VARCHAR2, TAB_COL_RECS OUT VARCHAR2) IS
      match_count integer;
      qry_str varchar2(1000);
      CURSOR TAB_COL_CURSOR IS 
          SELECT TABLE_NAME,COLUMN_NAME,OWNER,DATA_TYPE FROM ALL_TAB_COLUMNS WHERE DATA_TYPE in ('NUMBER','VARCHAR2') AND OWNER='SCOTT';
          BEGIN  
            FOR TAB_COL_REC  IN TAB_COL_CURSOR
            LOOP
              qry_str := 'SELECT COUNT(*) FROM '||TAB_COL_REC.OWNER||'.'||TAB_COL_REC.TABLE_NAME|| 
              ' WHERE '||TAB_COL_REC.COLUMN_NAME;
               IF TAB_COL_REC.DATA_TYPE = 'NUMBER' THEN
                      qry_str := qry_str||'='||SEARCH_STR; 
               ELSE
                       qry_str := qry_str||' like '||SEARCH_STR; 
               END IF;
                       --dbms_output.put_line( qry_str );
                EXECUTE IMMEDIATE  qry_str  INTO match_count;
                IF match_count > 0 THEN          
                   dbms_output.put_line( qry_str );
                  --dbms_output.put_line( TAB_COL_REC.TABLE_NAME ||' '||TAB_COL_REC.COLUMN_NAME ||' '||match_count);     
                    TAB_COL_RECS := TAB_COL_RECS||'@@'||TAB_COL_REC.TABLE_NAME||'##'||TAB_COL_REC.COLUMN_NAME;
                END IF; 
          END LOOP;
     END SEARCH_DB;    

Выполнение инструкции

  DECLARE
    SEARCH_STR VARCHAR2(200);
    TAB_COL_RECS VARCHAR2(200);
    BEGIN
      SEARCH_STR := 10;
      SEARCH_DB(
        SEARCH_STR => SEARCH_STR,
        TAB_COL_RECS => TAB_COL_RECS
      );
     DBMS_OUTPUT.PUT_LINE('TAB_COL_RECS = ' || TAB_COL_RECS);
     END;

Результаты выборки

Connecting to the database test.
SELECT COUNT(*) FROM SCOTT.EMP WHERE DEPTNO=10
SELECT COUNT(*) FROM SCOTT.DEPT WHERE DEPTNO=10
TAB_COL_RECS = @@EMP##DEPTNO@@DEPT##DEPTNO
Process exited.
Disconnecting from the database test.
30
задан Ates Goral 5 May 2010 в 17:26
поделиться

11 ответов

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

Поскольку std::map является ассоциативным контейнером, нет четкого заранее определенного диапазона ключей, которые должны существовать (или не существовать) на карте (в отличие от совершенно разных ситуация с std::vector). Это означает, что с помощью std::map вам нужны как непересекающиеся, так и вставные функции поиска. Можно перегрузить [] в неинтегрирующем режиме и обеспечить функцию для вставки. Или можно сделать наоборот: перегрузка [] в качестве оператора вставки и предоставление функции для неинтерактивного поиска. Итак, кто-то когда-то решил следовать последнему подходу. Вот и все.

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

8
ответ дан AnT 17 August 2018 в 16:12
поделиться
  • 1
  • 2
    @ n1ck: нотация [] очень хорошо фиксирована в умах людей. Теоретически было бы невозможно использовать его, но я не думаю, что это было очень вероятно. – David Thornley 28 October 2009 в 21:47
  • 3
    Причина, данная выше Павлом Минаевым, довольно убедительна. – hplbsh 29 October 2009 в 12:48
  • 4
    Который из? Что это «долговременная конвенция»? Может быть, правда, но не убедительно. Что нет способа узнать, находится ли это в левой части задания? Это не совсем убедительно, поскольку он может просто выбросить исключение или потребовать неопределенного поведения. Помните, исходный вопрос заключался в том, почему он отличается от std::vector. – AnT 29 October 2009 в 14:47

Невозможно избежать создания объекта, потому что оператор [] не знает, как его использовать.

myMap["apple"] = "green";

или

char const * cColor = myMyp["apple"];

Я предлагаю, чтобы контейнер карты добавлял функцию, подобную

if( ! myMap.exist( "apple")) throw ...

, ее намного проще и лучше читать, чем

if( myMap.find( "apple") != myMap.end()) throw ...

-1
ответ дан Ethan Heilman 17 August 2018 в 16:12
поделиться
  • 1
    Не уверен, что вы имеете в виду & quot; потому что оператор [] не знает, как его использовать & quot ;. Если вы прочтете мой ответ на другие ответы, как я уже сказал, мое первое ожидание состояло бы в том, чтобы действовать как векторный и крах по неверному индексу. т.е. вектор & lt; int & gt; v; v [1] = 1; сбой, почему бы и нет с картой? – n1ckp 12 July 2013 в 21:57
  • 2
    @ n1ckp В случае вектора присваивание индексу за пределами текущего размера недопустимо. На карте, однако, можно присвоить индекс, который в настоящее время не существует. – BlueSilver 28 February 2014 в 14:37
  • 3
    @BlueSilver: на самом деле это мой вопрос, почему это разрешено для карты (но не для вектора)? Я знаю, как работает этот класс, я просто хочу знать, почему это было сделано именно так. Пожалуйста, прочитайте другие комментарии и ответы, потому что я думаю, что это уже обсуждалось. – n1ckp 28 February 2014 в 21:35

Его назначение предназначено для назначения:


void test()
{
   std::map<std::string, int >myMap;
   myMap["hello"] = 5;
}
4
ответ дан EToreo 17 August 2018 в 16:12
поделиться
  • 1
    Если это была основная причина, то постоянная карта вернула бы постоянную ссылку, которой нельзя назначить, и operator[] для постоянных карт не нужно было бы создавать значение. Но для постоянных карт нет даже operator[], вы должны ошибаться. – sbi 28 October 2009 в 20:40
  • 2
    Я не уверен, как это делает меня неправильным ... похоже, если нет & lt; pre & gt; operator [] & lt; / pre & gt; на постоянной карте, это просто доказывает мою точку зрения. – EToreo 28 October 2009 в 21:17
  • 3
    То, что для постоянных карт нет operator[], кажется, указывает, что operator[] существует чисто для модификации карт. Я как-то должен неправильно понимать то, что вы делаете. Если дизайнеры STL не думали, что любой operator[] имеет смысл для постоянных карт, они, очевидно, видели весь смысл operator[] при изменении карты, например, с заданием в ответе ... – sth 28 October 2009 в 21:18
  • 4
    Имея operator[], есть две совершенно разные семантики в зависимости от того, является ли карта const или не звучит как плохая идея для меня. Так оно и есть, [] имеет определенную четко определенную семантику, которая просто не поддерживается для отображения const - следовательно, ее нет. – Pavel Minaev 28 October 2009 в 21:19
  • 5
    @EToreo & amp; sth: Я вижу, что мой момент был несколько слабым. <sheepish_grin> Позвольте мне ... Как это, operator[] выполняет две цели: вы можете использовать его для доступа к существующему элементу, и вы можете вставлять элементы. Для обоих существуют специальные функции, поэтому, по-видимому, это комбинация, почему существует operator[]. Для семантики добавления у вас есть insert(), для семантики доступа у вас есть find() - за исключением того, что find() может возвращать «несуществующий элемент», в то время как оператор не может. Семантика вставки необходима для для добавления и поиска для работы с использованием operator[]. – sbi 28 October 2009 в 22:04

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

Также существует принципиальное отличие в том, как обычно используется карта. С вектором обычно существует четкое разграничение между вещами, добавляемыми к вектору, и вещами, которые работают с тем, что уже есть в векторе. С картой это гораздо менее верно - это much более распространено, чтобы видеть код, который манипулирует элементом, который есть, если он есть, или добавляет новый элемент, если он еще не существует. Конструкция оператора [] для каждого отражает это.

3
ответ дан Jerry Coffin 17 August 2018 в 16:12
поделиться
  • 1
    Ну, я не уверен, что добавление нового элемента в вектор, когда индекс выходит за пределы диапазона без вмешательства пользователя, будет именно тем поведением, которое я хочу. Если я получаю доступ к внешнему массиву, это, вероятно, потому, что я сделал ошибку где-то в моем коде. Я не хочу, чтобы язык создавал для меня. Я даю вам +1 для второй части, хотя это не мой личный опыт работы с картами. – n1ckp 28 October 2009 в 21:48

Ответ заключается в том, что они хотели, чтобы реализация была удобной и быстрой.

Основная реализация вектора - это массив. Поэтому, если в массиве 10 записей, и вы хотите ввести 5, T & amp; vector :: operator [] (5) функция просто возвращает headptr + 5. Если вы запрашиваете запись 5400, она возвращает headptr + 5400.

Основная реализация карты обычно является деревом. Каждый узел распределяется динамически, в отличие от вектора, который стандарт требует смежного. Итак, nodeptr + 5 ничего не значит, а map ["some string"] не означает rootptr + offset ("some string").

Как и в случае с картами, vector имеет getAt (), если вы требуется проверка границ. В случае векторов проверка границ считалась ненужной для тех, кто этого не хотел. В случае с картами единственный способ не возвращать ссылку - это исключение, которое также считается ненужной для тех, кто этого не хочет.

1
ответ дан jmucchiello 17 August 2018 в 16:12
поделиться
  • 1
    Не могли ли они вернуть неверную ссылку, например, если вы разыменовали std :: map 'end ()? – n1ckp 28 October 2009 в 21:32
  • 2
  • 3
    n1ck, подумайте о логическом потоке. Чтобы вставить, программа должна найти, что положить запись в дерево. Эта обработка имеет стоимость. Поскольку наиболее вероятное действие после того, как не найти значение, это вставить его, почему бы просто не \ \ \ \ сделать вставку автоматически. – jmucchiello 28 October 2009 в 21:59
  • 4
  • 5
    @jmucchiello: Хорошие комментарии. Я просто нахожу использование оператора [] неинтуитивным для этой цели, но да, ваше собственное право. – n1ckp 28 October 2009 в 22:02

Стандарт говорит (23.3.1.2/1), что оператор [] возвращает (*((insert(make_pair(x, T()))).first)).second. Вот в чем причина. Он возвращает ссылку T&. Невозможно вернуть неверную ссылку. И он возвращает ссылку, потому что это очень удобно, я думаю, не так ли?

10
ответ дан Kirill V. Lyadvinsky 17 August 2018 в 16:12
поделиться
  • 1
    Извините, возможно, мой вопрос был недостаточно ясен, но я прошу причину этого стандарта. – n1ckp 28 October 2009 в 20:36
  • 2
    Хорошо, что operator[] возвращает ссылку. Поэтому он должен вставить что-то, потому что нет способа вернуть неверную ссылку. – Kirill V. Lyadvinsky 28 October 2009 в 20:37
  • 3
    Потому что исключение - для исключительных случаев. – Kirill V. Lyadvinsky 28 October 2009 в 20:41
  • 4
    @sbi: если вы уже не знаете, что он существует? Но да, я просто понял, что если бы это сработало, как хотелось бы, это было бы находкой, спасибо. – n1ckp 28 October 2009 в 21:00
  • 5
    Очень похоже на мысли. Каждый раз, когда я когда-либо использовал карту для поиска, мне приходилось проверять, вернётся ли поиск, а затем выбросить исключение, потому что это единственная подходящая вещь. – GManNickG 28 October 2009 в 21:02

map.insert (ключ, элемент); что ключ находится на карте, но не перезаписывает существующее значение.

map.operator [key] = item; что ключ находится на карте и перезаписывает любое существующее значение с помощью элемента.

Обе эти операции достаточно важны, чтобы гарантировать одну строку кода. Дизайнеры, вероятно, выбрали, какая операция была более интуитивной для оператора [] и создала вызов функции для другого.

1
ответ дан me. 17 August 2018 в 16:12
поделиться

Рассмотрим такой вход - 3 блока, каждый блок 2 строки, первая строка - количество элементов во втором:

5
13 20 22 43 146
4
13 22 43 146
5
13 43 67 89 146

Проблема: вычислить число целых чисел, которые присутствуют во втором линий всех трех блоков. (Для этого ввода образца выход должен быть 3 до 13, 43 и 146 присутствуют во вторых строках всех трех блоков)

Посмотрите, насколько хорошо этот код:

int main ()
{
    int n, curr;
    map<unsigned, unsigned char> myMap;
    for (int i = 0; i < 3; ++i)
    {
        cin >> n;
        for (int j = 0; j < n; ++j)
        {
            cin >> curr;
            myMap[curr]++;
        }

    }

    unsigned count = 0;
    for (auto it = myMap.begin(); it != myMap.end(); ++it)
    {
        if (it->second == 3)
            ++count;
    }

    cout << count <<endl;
    return 0;
}

Согласно стандарту operator[] возвращается ссылка на (*((insert(make_pair(key, T()))).first)).second. Вот почему я мог написать:

myMap[curr]++;

, и он вставил элемент с ключом curr и инициализировал значение на ноль, если ключ не присутствовал на карте. А также он увеличил значение, несмотря на то, что элемент был на карте или нет.

Посмотрите, как просто? Это хорошо, не так ли? Это хороший пример того, что это действительно удобно.

0
ответ дан Narek 17 August 2018 в 16:12
поделиться
  • 1
    Хм, да, это может быть удобно и приятно, но зачем использовать оператор [], а не более явную именованную функцию? Поведение не выглядит интуитивно понятным для меня, и поэтому я считаю странным поведение какого-то типа operator [] вместо использования функции с явным именем для чего-то, что делает какую-то странную обработку, которая не является непосредственно интуитивной. Я не говорю, что это нехорошо, но почему оператор [] имеет такое поведение, он мог бы быть стандартной функцией. – n1ckp 17 May 2013 в 20:04
  • 2
    Думаю, у вас есть хороший опыт на другом языке программирования, не так ли? :) – Narek 18 May 2013 в 09:46
  • 3
    да и нет, почему вы спрашиваете? Я в основном парень на С ++, но я знаю пару других языков. – n1ckp 21 May 2013 в 22:08
  • 4
    Я думал, что вы не парень C ++, поэтому вы задаете этот вопрос. Но похоже, есть еще одна причина :) – Narek 21 May 2013 в 22:14
  • 5
    Причина, по которой я задал этот вопрос, состоит в том, что поведение не является интуитивным, и я хотел знать, ПОЧЕМУ он был закодирован таким образом. Я, конечно, знал, КАК это действовало, поэтому у меня не было проблем с этим. Спасибо за ваш ответ, но это не то, что я искал. – n1ckp 23 May 2013 в 20:17
1
ответ дан Nikolai Fetissov 17 August 2018 в 16:12
поделиться

Он позволяет вставлять новые элементы с помощью operator[], например:

std::map<std::string, int> m;
m["five"] = 5;

5 присваивается значение, возвращаемое m["five"], которое является ссылкой на вновь созданный элемент. Если operator[] не будет вставлять новые элементы, это не сработает.

3
ответ дан sth 17 August 2018 в 16:12
поделиться

Поскольку operator[] возвращает ссылку на само значение, поэтому единственный способ указать проблему - это выбросить исключение (и, как правило, STL редко выдает исключения).

Если вы не нравится это поведение, вы можете использовать map::find вместо этого. Он возвращает итератор вместо значения. Это позволяет ему возвращать специальный итератор, когда значение не найдено (оно возвращает map::end), но также требует от вас разыменования итератора, чтобы получить значение.

21
ответ дан ネロク 17 August 2018 в 16:12
поделиться
  • 1
    но не возвращает вектор ссылку? в чем тут разница? Извините, я не знаком с std :: map, поэтому, возможно, это очевидно из внутреннего. – n1ckp 28 October 2009 в 20:43
  • 2
    Неопределенное поведение позволяет получить доступ к вектору за пределами с помощью []. Я предполагаю, что карта также может ссылаться на некоторое неопределенное поведение в этом случае, но вам это действительно понравится? С помощью вектора легко узнать, действительно ли указатель, с картой нет (вы могли бы называть сначала, и в этом случае было бы бессмысленно называть [], поскольку вы должны были уже найти элемент, который вы ищем). – UncleBens 28 October 2009 в 20:47
  • 3
    @ n1ck: std :: vector вернет недопустимую ссылку (потому что это легко сделать). У std :: map нет простого способа вернуть ссылку. – Martin York 28 October 2009 в 20:48
  • 4
    Традиционно интерфейс для карт (на всех языках, а не только на C ++) позволяет вам написать что-то вроде map[key] = value;, и карта заменит существующее значение или вставить новое по необходимости. Это давняя конвенция, поэтому неудивительно, что std::map следует за ней. Однако, поскольку operator[] не может определить, будет ли ссылка, которую он должен вернуть, будет использоваться с левой стороны operator= или нет, она всегда должна принимать худшее значение и, следовательно, вставить новый элемент. – Pavel Minaev 28 October 2009 в 21:18
  • 5
    @ N1ck: они могут быть старше, чем библиотека std. :) – sbi 28 October 2009 в 21:48