Индекс, присвоение и инкремент в одном операторе ведут себя по-другому в C++ и C#. Почему?

Если Вы не заботитесь о строках sub, чем простое

>>> 'a short sized string with spaces '.split()

Производительность:

>>> s = " ('a short sized string with spaces '*100).split() "
>>> t = timeit.Timer(stmt=s)
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
171.39 usec/pass

Или строковый модуль

>>> from string import split as stringsplit; 
>>> stringsplit('a short sized string with spaces '*100)

Производительность: Строковый модуль, кажется, работает лучше, чем строковые методы

>>> s = "stringsplit('a short sized string with spaces '*100)"
>>> t = timeit.Timer(s, "from string import split as stringsplit")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
154.88 usec/pass

, Или можно использовать механизм РЕ

>>> from re import split as resplit
>>> regex = '\s+'
>>> medstring = 'a short sized string with spaces '*100
>>> resplit(regex, medstring)

Производительность

>>> s = "resplit(regex, medstring)"
>>> t = timeit.Timer(s, "from re import split as resplit; regex='\s+'; medstring='a short sized string with spaces '*100")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
540.21 usec/pass

Для очень длинных строк, Вы не должны загружать всю строку в память и вместо этого или разделить строки или использовать итерационный цикл

5
задан Jon Seigel 7 April 2010 в 01:39
поделиться

7 ответов

Как отмечали другие, поведение этого кода undefined в C / C ++. Вы можете получить любой результат.

Поведение вашего кода C # строго определено стандартом C #.

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

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

Разработчики C # не верят, что неопределенное поведение простых выражений - это хорошо, и поэтому мы строго определили, что означают подобные выражения. Мы не можем согласиться с тем, что делает каждый компилятор C ++, потому что разные компиляторы C ++ дают разные результаты для такого рода кода, и поэтому мы не можем согласиться со всеми из них.

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

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

Как дизайн C # способствует устранению тонких ошибок:

http://blogs.msdn.com/ericlippert/archive/2007/08/14/c-and-the -пит-от-отчаяния. aspx

Какова точная связь между приоритетом, ассоциативностью и порядком выполнения в C #?

http://blogs.msdn.com/ericlippert/archive/2008/05/23/precedence-vs-associativity- vs-order.aspx

В каком порядке происходят побочные эффекты индексации, присваивания и увеличения?

http://blogs.msdn.com/ericlippert/archive/2009/08/10/precedence-vs- order-redux.aspx

11
ответ дан 18 December 2019 в 08:29
поделиться

Your C++ code could, in fact, do anything. arr[index] = ++index; invokes undefined behaviour.

4
ответ дан 18 December 2019 в 08:29
поделиться

The behaviour of using index and ++index inside the same assignment is unspecified in C++. You just can't just do that: write arr[index] = index + 1 and increment your variable after that. For that matter, with my C++ compiler on my machine I see arr[0] = 1, and arr[1] is untouched.

3
ответ дан 18 December 2019 в 08:29
поделиться

In the case of C++, at least, you're invoking undefined behavior by preincrementing and using index without a sequence point in between. If you feed that code to GCC with warnings enabled it will say:

preinc.cpp:6: warning: operation on ‘index’ may be undefined

I'm guessing that it's undefined as well in C#, but I don't know the language. For C and C++ at the very least though, the answer is that the compiler can do anything it wants without being wrong because your code is erroneous. There's no obligation for different compilers (or even the same compiler) to produce consistent results, either.

1
ответ дан 18 December 2019 в 08:29
поделиться

Note: Acording to @Eric Lippert's answer, the behavior is strictly defined for C#, so let me reword my answer on this.

This code:

arr[index] = ++index;

Is hard to read even if the C# compiler knows exactly how to evaluate it and in which order. For this reason alone it should be avoided.

The MSDN page on C# Operators goes so far as pointing out that this behaviour might be undefined, even though Eric points out it is not. The fact that multiple sources of documentation (I'll trust Eric on this however) gets it different is also a tell that this might be something best left alone.

1
ответ дан 18 December 2019 в 08:29
поделиться

The result of the C++ version will not always be as you write as you are invoking undefined behaviour. In C++ you will get undefined behaviour if you use the value of a variable in an expression when that variable is also modified the same expression unless reading that value is part of determining the value to be written, or the expression contains a sequence point between the read and the write.

In your expression, you are reading the value of index to determine where to assign the result of the right hand side of the =, but the right hand sub-expression also modifies index.

0
ответ дан 18 December 2019 в 08:29
поделиться

индекс в C # является типом значения, что означает, что вы возвращаете новый экземпляр значения, когда выполняете с ним операции.

Если вы представляете его как процедуру вместо оператора, процедура будет выглядеть так:

public int Increment(int value)
{
   int returnValue=value+1;
   return returnValue;
}

C ++, однако, работает со ссылкой на объект, поэтому процедура будет выглядеть так:

int Increment(int &value)
{
   value=value+1;
   return value;
}

Примечание: если вы применяли оператор к объекту (скажем, перегружали ++ оператор), то C # будет вести себя как C ++, поскольку типы объектов передаются как ссылки.

-1
ответ дан 18 December 2019 в 08:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: