Разница между точечной нотацией и -> в цели C - PullRequest
4 голосов
/ 14 ноября 2011

Я пытаюсь использовать как можно меньше памяти в своем коде. Я попробовал два способа отправки объекта пользовательского класса в метод. Я не уверен, есть ли разница между этими двумя подходами. Скажем, у меня есть 2 класса, Class1 и Class2 каждый со своими переменными класса и, конечно, методами.

Весь код написан в Class1

Подход 1:

Class2 *class2Object = [[Class2 alloc] init];

[self doSomething: class2Object];

[class2Object release];

-(void) doSomething: (Class2 *) var {
int a = var.a;
}

Подход 2:

Class2 *class2Object = [[Class2 alloc] init];

[self doSomething: &class2Object];

[class2Object release];

-(void) doSomething: (Class2 **) var {
int a = var->a;
}

Есть ли разница в производительности между этими двумя методами? Является ли второй подход совершенно бессмысленным? Почему я могу использовать точечную запись в подходе 1, а использовать -> в подходе 2?

Спасибо.

Ответы [ 3 ]

4 голосов
/ 14 ноября 2011

Есть ли разница в производительности между этими двумя методами?

действительно, разница в производительности незначительна из-за того, что в подходе 2 у вас есть еще одно косвенное указание (то есть разыменование указателя, см. Также ниже); Итак, подход 1 сэкономит вам несколько тактов.

Второй подход совершенно бессмысленный?

подход 2 полезен, например, когда вы хотите выделить новый экземпляр типа Class2 и передать его вызывающей стороне через тот же аргумент; говорят:

 - (bool)cloneObject:(Class2 **)var;

Вы передаете объект в; объект клонируется и возвращается в var; так как изменяется адрес самого объекта, вам нужно иметь указатель на указатель на объект, чтобы установить новый адрес; возвращаемое значение указывается только в том случае, если операция была выполнена правильно.

Конечно, в этом примере было бы более естественным сделать:

     - (Class2)cloneObject:(Class2*)var;

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

Почему я могу использовать точечную запись в подходе 1, а использовать -> в подходе 2?

во втором случае вы должны использовать ->, потому что вы не имеете дело с указателем на объект напрямую; вы имеете дело с указателем на указатель на объект; в таких случаях вам нужно, в первую очередь, «разыменовать» ваш указатель (т. е. применить оператор *), чтобы получить указатель на объект, а затем получить доступ к последнему, как вы сделали бы иначе; это можно написать так:

 (*var).a

здесь var - указатель на указатель на объект Class2; *var является результатом его разыменования, поэтому у вас есть указатель на объект Class2; наконец, .a - это синтаксис для доступа к свойству объекта. синтаксис:

var->a

- это просто «сокращение» для операций, описанных выше.

4 голосов
/ 14 ноября 2011

В подходе 1 вы получаете доступ к свойству с именем a.Это выглядит хорошо.

В подходе 2 я шокирован тем, что ваш код компилируется.Также совершенно бесполезно передавать указатель на class2Object.Единственная причина когда-либо передавать указатели на объекты состоит в том, что вызываемый метод должен обновить этот параметр (например, если это выходной параметр), что здесь не так.Передача указателя на объект абсолютно не влияет на использование памяти.Объекты уже хранятся как указатели (именно поэтому вы пишете Class2 *), поэтому нет необходимости в копировании объектов, как вы могли бы видеть при передаче объекта, выделенного из стека, в C ++ (Obj-C не имеет понятия стека-распределенные объекты, за исключением блоков, что является странным угловым случаем, о котором вам не нужно беспокоиться).

В общем, просто перейдите к подходу 1 здесь.

2 голосов
/ 15 ноября 2011
Синтаксис

x->y в Си такой же, как и (*x).y, поэтому нет никакой разницы в том, что он делает, за исключением дополнительного (ненужного) получения и разыменования указателя, как говорили другие. Но я хотел бы остановиться на более интересном связанном моменте.

Вы должны понимать, что в

-(void) doSomething: (Class2 *) var {
   int a = var.a;
}

точка доступа к собственности. (Это не может быть доступ к структурному полю, поскольку var является указателем.) Это точно эквивалентно int a = [var a]; (если для метода получения явно не задан другой метод).

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

Если свойство a синтезировано из переменной экземпляра a (можно было бы назвать что-то еще, мы сейчас скажем a), вместо того, чтобы обращаться к переменной через свойство, вы можете вместо этого объявить его открытым (через @public; в противном случае переменные экземпляра защищены по умолчанию), а затем обращаться к нему напрямую через ->:

-(void) doSomething: (Class2 *) var {
   int a = var->a;
}

(Обратите внимание, что это отличается от того, что у вас есть, потому что var - это сам указатель объекта, а не указатель на указатель.)

Однако общедоступные переменные экземпляра, как правило, считаются плохим стилем и не приветствуются. Использование его нарушает абстракцию в объектно-ориентированном программировании. Я приведу это здесь для полноты, потому что технически это самый быстрый способ доступа к переменной экземпляра.

...