Брутально и бессердечно о программировании и проектировании
ГлавнаяАртПаттерныАнтипаттерныТест-драйвЗаметкиВопрос-ответКнигорецензииСправочная

#1 2007-09-11 15:08:28

Vitamin
Пользователь
Откуда: Таганрог
Зарегистрирован: 2007-08-25
Сообщений: 19
Вебсайт

(*iter).member или iter->member ?

Собственно, сабж.
У кого-то из столпов С++-изма встречал разъяснение, что первый метод лучше. Сейчас уже не помню у кого (вроде Мейерс). Что по этому поводу думает многоуважаемый All?


With best wishes

Неактивен

 

#2 2007-09-24 16:31:56

RedLord
Пользователь
Зарегистрирован: 2007-06-05
Сообщений: 14

Re: (*iter).member или iter->member ?

правильно, Мейерс. речь идет об STL.

-> - можно перегрузить. и STL не накладывает ограничение.
а вот (*it) _обязан_ возвращать ссылку на объект

Неактивен

 

#3 2007-09-25 00:18:20

Автор
Пользователь
Зарегистрирован: 2007-05-16
Сообщений: 156

Re: (*iter).member или iter->member ?

RedLord

Так ведь и операцию разыменования можно перегружать ;-)

Неактивен

 

#4 2007-09-25 09:41:26

Vitamin
Пользователь
Откуда: Таганрог
Зарегистрирован: 2007-08-25
Сообщений: 19
Вебсайт

Re: (*iter).member или iter->member ?

-> можно перегрузить у контейнеризированного класса, а у итератора оно вроде как гвоздями прибито...


With best wishes

Неактивен

 

#5 2007-09-25 15:47:20

RedLord
Пользователь
Зарегистрирован: 2007-06-05
Сообщений: 14

Re: (*iter).member или iter->member ?

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

C++ 14882:

All iterators i support the expression *i, resulting in a value
of some class, enumeration, or built-in type T, called the value type of the iterator. All iterators i for which
the expression (*i).m is well-defined, support the expression i->m with the same semantics as (*i).m.

для i-> результат может быть не T*

Отредактированно RedLord (2007-09-25 21:50:10)

Неактивен

 

#6 2008-02-21 22:11:57

indexless
Пользователь
Зарегистрирован: 2008-02-21
Сообщений: 1

Re: (*iter).member или iter->member ?

RedLord написал:

-> - можно перегрузить. и STL не накладывает ограничение.
а вот (*it) _обязан_ возвращать ссылку на объект

#include <iostream>

class X
{
public:
    void f() { std::cout << "Yoyo!\n"; }
    int i;
};

int main()
{
    X *x = 0;

    (*x).f();
    std::cout << x->i << "\n";

    return 0;
}

Вывод:
Yoyo!
Segmentation fault

Обращение к x->i, конечно, уронило программу, а вот (*x).f() сработало :) Компилятор GNU g++ v4.2.3, с ключом -O0  Это иллюстрирует, что запись (*x).<чтонибудь> вовсе не означает, что кто-то что-то здесь будет разыменовывать. (*x) или x-> означает принадлежность функции к типу, и только. А вот область памяти, на которую указывает ее неявный аргумент this, ей понадобится только тогда, когда в теле ф-ции будет обращение к полям типа. Если обращение по адресу this не требуется, можно запросто сделать ((X *)чтоугодно)->f(), и это будет работать.

Отредактированно indexless (2008-02-21 22:22:24)

Неактивен

 

#7 2008-02-22 11:30:28

Автор
Пользователь
Зарегистрирован: 2007-05-16
Сообщений: 156

Re: (*iter).member или iter->member ?

indexless

В вашем примере x->f() сработает, а (*x).i - нет. Вы верно сказали, что падение будет только если функция обратится к членам класса, но в вашем примере никакой разницы между operator . и operator -> нет.

Неактивен

 

#8 2008-12-05 00:20:55

addword
Пользователь
Откуда: Одесса, Украина
Зарегистрирован: 2008-11-26
Сообщений: 26
Вебсайт

Re: (*iter).member или iter->member ?

Да, стандарт требует. Но есть НО.

Это "но" начинает проявляться тогда, когда вы работаете с контейнером интеллектуальных указателей (например shared_ptr). У этих товарищей, как известно, перегружен оператор ->. Так вот, если вы хотете вызвать функцию класса, объектом которого владеет такой указатель, через итератор на него, то вам нужно использовать что-то типа iter->->foo(). А это, понятное дело, не поддерживается. Так что только (*iter)->foo().

Таким образом, код "знает" что именно хранится в контейнере. А это абсолютно неприемлемо для обобщённого кода. И, естественно, не годится при написании расширений STL. (см. Willson)

Так что? работать с разыменованым итератором это более обобщённо. И вообще, это хорошая привычка ("выдох в воду") (от меня респект автору за хорошую метафору).

Неактивен

 

#9 2009-01-02 11:01:53

ud
Пользователь
Откуда: Россия, Томск
Зарегистрирован: 2009-01-02
Сообщений: 4
Вебсайт

Re: (*iter).member или iter->member ?

addword написал:

Так вот, если вы хотете вызвать функцию класса, объектом которого владеет такой указатель, через итератор на него, то вам нужно использовать что-то типа iter->->foo(). А это, понятное дело, не поддерживается. Так что только (*iter)->foo().

Еще можно iter->get()->foo(); :)

Неактивен

 

#10 2009-01-04 17:14:11

addword
Пользователь
Откуда: Одесса, Украина
Зарегистрирован: 2008-11-26
Сообщений: 26
Вебсайт

Re: (*iter).member или iter->member ?

Да, так тоже можно. Но я рекомендую использовать технику разыменования итератора. Это так сказать, хорошая привычка, "выдох под воду" (см. статью в разделе "Арт").

Как я уже говорил, это неприемлемо для обобщённого кода.
Код из примера с использованием get(), подходит для случаев когда в контейнере хранятся не указатели, а объекты класса, предоставляющего функцию get(), возвращающую указатель. То есть код получился ещё менее обобщённым.

Неактивен

 

#11 2009-01-05 10:16:37

ud
Пользователь
Откуда: Россия, Томск
Зарегистрирован: 2009-01-02
Сообщений: 4
Вебсайт

Re: (*iter).member или iter->member ?

Спасибо за разъяснение!

Неактивен

 

Board footer

Статистика
© 2007—2010 Inside C++ Коммерческие услугиКонтактная информация