Различие между преинкрементом и постинкрементом в цикле?

Всякий раз, когда код передает функцию или объект в API, возникает риск создания ссылок на объекты, что предотвратит сборку мусора. Это может привести к утечке памяти.

Метод $on возвращает функцию, которая может использоваться для отмены привязки обработчика событий:

this.subscribe = function( scope, cb )
{
    var deRegister = {};
    deRegister.ActionChanged = $rootScope.$on('action-changed', cb);
    deRegister.ProjectChanged = $rootScope.$on('project-changed', cb);
    deRegister.FileChanged = $rootScope.$on('file-changed', cb);

    scope.$on( '$destroy', function() {
        deRegister.ActionChanged();
        deRegister.ProjectChanged();
        deRegister.FileChanged();
        deRegister = null; //release deRegister object
        scope = null;      //release scope reference
        cb = null;         //release callback function reference
    ));
};

В дополнение к отмене регистрации обработчиков событий, код должен освобождать любые созданные ссылки на объекты. [ 114]

294
задан L. F. 31 July 2019 в 23:51
поделиться

14 ответов

++ известен как постфикс.

добавляют 1 к a, возвращает старое значение.

++ известного как префикс.

добавляют 1 к a, возвращает новое значение.

C#:

string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
    Console.WriteLine(++i);
}
Console.WriteLine("");

i = 0;
foreach (string item in items)
{
    Console.WriteLine(i++);
}

Вывод:

1
2
3
4

0
1
2
3

foreach и while циклы зависят, на котором инкременте вводят Вас использование. С для циклов как ниже его не имеет никакого значения, поскольку Вы не используете возвращаемое значение меня:

for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }

0 1 2 3 4
0 1 2 3 4

, Если значение, как оценено используется затем, тип инкремента становится значительным:

int n = 0;
for (int i = 0; n < 5; n = i++) { }
224
ответ дан TT-- 23 November 2019 в 01:36
поделиться

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

кроме того, в c++ является обычно самым безопасным использовать преинкрементную форму (++i), потому что это более легко оптимизировано. (Scott Langham победил меня к этому лакомому кусочку . Прокляните Вас, Scott)

-2
ответ дан Community 23 November 2019 в 01:36
поделиться

Может быть различие для циклов. Это - практическое применение post/pre-increment.

        int i = 0;
        while(i++ <= 10) {
            Console.Write(i);
        }
        Console.Write(System.Environment.NewLine);

        i = 0;
        while(++i <= 10) {
            Console.Write(i);
        }
        Console.ReadLine();

, В то время как первые количества к 11 и циклы 11 раз, второе не делает.

Главным образом это скорее используется в простом в то время как (x-> 0); - Цикл для итерации, например, всех элементов массива (освобождающий foreach-конструкции здесь).

1
ответ дан Leonidas 23 November 2019 в 01:36
поделиться

Как говорит @Jon B, нет никакого различия в для цикла.

, Но в while или do...while цикл, Вы могли найти некоторые различия при создании сравнения с ++i или i++

while(i++ < 10) { ... } //compare then increment

while(++i < 10) { ... } //increment then compare
2
ответ дан Community 23 November 2019 в 01:36
поделиться

В JavaScript из-за следующего я ++ могу быть лучше для использования:

var i=1;
alert(i++); // before, 1. current, 1. after, 2.
alert(i); // before, 2. current, 2. after, 2.
alert(++i); // before, 2. current, 3 after, 3.

, В то время как массивы (я думаю все) и некоторые другие функции и вызовы используют 0 в качестве начальной точки, которую необходимо было бы установить i на-1, чтобы заставить цикл работать с массивом при использовании ++ я .

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

2
ответ дан xaddict 23 November 2019 в 01:36
поделиться

Существует больше к ++ я и я ++, чем циклы и различия в производительности. ++ я возвращаю l-значение, и я ++ возвращаю r-значение. На основе этого существует много вещей, которые можно сделать к (++ i), но не к (я ++).

1- It is illegal to take the address of post increment result. Compiler won't even allow you.
2- Only constant references to post increment can exist, i.e., of the form const T&.
3- You cannot apply another post increment or decrement to the result of i++, i.e., there is no such thing as I++++. This would be parsed as ( i ++ ) ++ which is illegal.
4- When overloading pre-/post-increment and decrement operators, programmers are encouraged to define post- increment/decrement operators like:

T& operator ++ ( )
{
   // logical increment
   return *this;
}

const T operator ++ ( int )
{
    T temp( *this );
    ++*this;
    return temp;
}
3
ответ дан Tanveer Badar 23 November 2019 в 01:36
поделиться

Да, существует. Различие находится в возвращаемом значении. Возвращаемое значение "++ я" буду значением после постепенное увеличение i. Возврат "я ++" буду значением прежде постепенное увеличение. Это означает, что кодируют, который похож на следующее:

int a = 0;
int b = ++a; // a is incremented and the result after incrementing is saved to b.
int c = a++; // a is incremented again and the result before incremening is saved to c.

Поэтому быть 2, и b и c каждый был бы 1.

я мог переписать код как это:

int a = 0; 

// ++a;
a = a + 1; // incrementing first.
b = a; // setting second. 

// a++;
c = a; // setting first. 
a = a + 1; // incrementing second. 
5
ответ дан David Morton 23 November 2019 в 01:36
поделиться

Вот Образец Java, и Байт-код, пост - и преинкремент не показывает различия в Байт-коде:

public class PreOrPostIncrement {

    static int somethingToIncrement = 0;

    public static void main(String[] args) {
        final int rounds = 1000;
        postIncrement(rounds);
        preIncrement(rounds);
    }

    private static void postIncrement(final int rounds) {
        for (int i = 0; i < rounds; i++) {
            somethingToIncrement++;
        }
    }

    private static void preIncrement(final int rounds) {
        for (int i = 0; i < rounds; ++i) {
            ++somethingToIncrement;
        }
    }
}

И теперь для байт-кода (javap - частный-c PreOrPostIncrement):

public class PreOrPostIncrement extends java.lang.Object{
static int somethingToIncrement;

static {};
Code:
0:  iconst_0
1:  putstatic   #10; //Field somethingToIncrement:I
4:  return

public PreOrPostIncrement();
Code:
0:  aload_0
1:  invokespecial   #15; //Method java/lang/Object."<init>":()V
4:  return

public static void main(java.lang.String[]);
Code:
0:  sipush  1000
3:  istore_1
4:  sipush  1000
7:  invokestatic    #21; //Method postIncrement:(I)V
10: sipush  1000
13: invokestatic    #25; //Method preIncrement:(I)V
16: return

private static void postIncrement(int);
Code:
0:  iconst_0
1:  istore_1
2:  goto    16
5:  getstatic   #10; //Field somethingToIncrement:I
8:  iconst_1
9:  iadd
10: putstatic   #10; //Field somethingToIncrement:I
13: iinc    1, 1
16: iload_1
17: iload_0
18: if_icmplt   5
21: return

private static void preIncrement(int);
Code:
0:  iconst_0
1:  istore_1
2:  goto    16
5:  getstatic   #10; //Field somethingToIncrement:I
8:  iconst_1
9:  iadd
10: putstatic   #10; //Field somethingToIncrement:I
13: iinc    1, 1
16: iload_1
17: iload_0
18: if_icmplt   5
21: return

}
7
ответ дан Cœur 23 November 2019 в 01:36
поделиться

Один (++ i) преинкремент, один (я ++) постинкремент. Различие находится в том, какое значение сразу возвращено от выражения.

// Psuedocode
int i = 0;
print i++; // Prints 0
print i; // Prints 1
int j = 0;
print ++j; // Prints 1
print j; // Prints 1

Редактирование: Ой, полностью проигнорированный сторона цикла вещей. Нет никакого фактического различия в для циклов, когда это - часть 'шага' (для (...;...;)), но это может сыграть роль в других случаях.

14
ответ дан Cody Brocious 23 November 2019 в 01:36
поделиться

Поскольку этот код показывает (см. скрываемый MSIL в комментариях), компилятор C# 3 не делает различия между мной ++ и ++ я в для цикла. Если бы значение меня ++ или ++ я брался, то определенно было бы различие (это было скомпилировано в Studio Visutal 2008 / Сборка конечных версий):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PreOrPostIncrement
{
    class Program
    {
        static int SomethingToIncrement;

        static void Main(string[] args)
        {
            PreIncrement(1000);
            PostIncrement(1000);
            Console.WriteLine("SomethingToIncrement={0}", SomethingToIncrement);
        }

        static void PreIncrement(int count)
        {
            /*
            .method private hidebysig static void  PreIncrement(int32 count) cil managed
            {
              // Code size       25 (0x19)
              .maxstack  2
              .locals init ([0] int32 i)
              IL_0000:  ldc.i4.0
              IL_0001:  stloc.0
              IL_0002:  br.s       IL_0014
              IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0009:  ldc.i4.1
              IL_000a:  add
              IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
              IL_0010:  ldloc.0
              IL_0011:  ldc.i4.1
              IL_0012:  add
              IL_0013:  stloc.0
              IL_0014:  ldloc.0
              IL_0015:  ldarg.0
              IL_0016:  blt.s      IL_0004
              IL_0018:  ret
            } // end of method Program::PreIncrement             
             */
            for (int i = 0; i < count; ++i)
            {
                ++SomethingToIncrement;
            }
        }

        static void PostIncrement(int count)
        {
            /*
                .method private hidebysig static void  PostIncrement(int32 count) cil managed
                {
                  // Code size       25 (0x19)
                  .maxstack  2
                  .locals init ([0] int32 i)
                  IL_0000:  ldc.i4.0
                  IL_0001:  stloc.0
                  IL_0002:  br.s       IL_0014
                  IL_0004:  ldsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0009:  ldc.i4.1
                  IL_000a:  add
                  IL_000b:  stsfld     int32 PreOrPostIncrement.Program::SomethingToIncrement
                  IL_0010:  ldloc.0
                  IL_0011:  ldc.i4.1
                  IL_0012:  add
                  IL_0013:  stloc.0
                  IL_0014:  ldloc.0
                  IL_0015:  ldarg.0
                  IL_0016:  blt.s      IL_0004
                  IL_0018:  ret
                } // end of method Program::PostIncrement
             */
            for (int i = 0; i < count; i++)
            {
                SomethingToIncrement++;
            }
        }
    }
}
15
ответ дан Joe Erickson 23 November 2019 в 01:36
поделиться

Так как Вы спрашиваете о различии в цикле, я предполагаю, что Вы имеете в виду

for(int i=0; i<10; i++) 
    ...;

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

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

for(int i=0, a = 0; i<10; a = i++) 
    ...;

Теперь, там различие, потому что, поскольку другие указывают, i++ средства инкремент, но оценивают к предыдущему значению , но ++i средства инкремент, но оценивают к i (таким образом, это оценило бы к новому значению). В вышеупомянутом случае, a присвоен предыдущее значение меня, в то время как я увеличен.

30
ответ дан Johannes Schaub - litb 23 November 2019 в 01:36
поделиться

В C# нет никакого различия при использовании в для цикла .

for (int i = 0; i < 10; i++) { Console.WriteLine(i); }

выводы то же самое как

for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }

Как другие указало при использовании в целом я ++ и ++ у меня есть тонкая все же значительная разница:

int i = 0;
Console.WriteLine(i++);   // Prints 0
int j = 0;
Console.WriteLine(++j);   // Prints 1

я ++ читаю значение, я затем увеличиваю его.

++ я увеличиваю значение, я затем читаю его.

82
ответ дан Cœur 23 November 2019 в 01:36
поделиться

Преинкремент ++ я инкременты значение меня и оценивает к новому увеличенному значению.

int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );

Постинкремент i ++ инкременты значение меня и оценивает к исходному неувеличенному значению.

int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );
<час>

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

Это вызвано тем, что при использовании постинкремента он может потребовать, чтобы компилятор должен был сгенерировать код, который создает дополнительную временную переменную. Это вызвано тем, что и предыдущие и новые значения переменной, увеличиваемой потребность, которая будет сохранена где-нибудь, потому что они могут быть необходимы в другом месте в оцениваемом выражении.

Так, в C++, по крайней мере, может быть различие в производительности, которое ведет Ваш выбор, которого можно использовать.

Это - главным образом только проблема, когда увеличиваемая переменная является определяемым пользователем типом с переопределенным ++ оператор. Для типов примитивов (интервал, и т.д.) нет никакого различия в производительности. Но, стоит придерживаться преинкрементного оператора как инструкции, если постинкрементный оператор не определенно, что требуется.

здесь существует еще некоторое обсуждение:
https://web.archive.org/web/20170405054235/http://en.allexperts.com/q/C-1040/Increment-operators.htm

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

<час>

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

Исправление: перегрузка ++ в C# позволяется. Это кажется, хотя, что по сравнению с C++, в c# Вы не можете перегрузить пред и отправить версии независимо. Так, я предположил бы что, если результат вызова ++ в C# не присваивается переменной или используется в качестве части сложного выражения, то компилятор уменьшил бы пред и версии сообщения ++ вниз для кодирования, который работает эквивалентно.

215
ответ дан Wilfred Hughes 23 November 2019 в 01:36
поделиться

Нет никакого фактического различия в обоих случаях' i', будет увеличен 1.

, Но существует различие при использовании его в выражении, например:

int i = 1;
int a = ++i;
// i is incremented by one and then assigned to a.
// Both i and a are now 2.
int b = i++;
// i is assigned to b and then incremented by one.
// b is now 2, and i is now 3
4
ответ дан CMS 23 November 2019 в 01:36
поделиться
Другие вопросы по тегам:

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