Может ли кто-нибудь объяснить в этом случае разницу между «ссылкой» и «указателем»? - PullRequest
6 голосов
/ 04 октября 2009

Когда я прочитал litb ответ на этот вопрос , я узнал, что передача массива по ссылке позволяет нам получить его размер. Я просто немного поиграл с кодом и попытался передать «функцию» по ссылке, и на удивление (по крайней мере, для меня) этот код компилируется:

void execute( void (&func)() ) // func is passed by reference!
{
    func();
}

Есть ли разница между последней функцией и этой:

void execute( void (*func)() ) // func is passed by pointer!
{
    func();
}

Я пробовал использовать VC2008, и он выдает разные результаты в каждом случае. Странно то, что компилятор лучше оптимизирует код в случае указателя на функцию:

void print()
{
    std::cout << "Hello References!";
}
void execute( void (&func)() ) // optimized
{
    func();
}
int main()
{
    00291020  call   print (291000h)
}
=========================================
// In this case, the compiler removes all function calls in the code!
void print() // optimized!
{
    std::cout << "Hello Pointers!";
}
void execute( void (*func)() ) // optimized
{
    func();
}
int main()
{
    002F1005  push  offset string "Hello References!" (2F2124h) 
    002F100A  push  eax  
    002F100B  call  std::operator<<<std::char_traits<char> > (2F1150h) 
}

Должна быть разница, хотя я ее не вижу, верно?

Примечание: код был скомпилирован с использованием VC2008, с включенными /O2 и /Ot.


РЕДАКТИРОВАТЬ :: Меня действительно интересует любая разница между ссылками на функции и указателями на функции. Я изучил полученный код сборки, чтобы посмотреть, как он переводится в каждом конкретном случае.

Ответы [ 4 ]

3 голосов
/ 04 октября 2009

Я думаю, что это связано с C ++ Standard 4.3:

Значение l типа функции T может быть преобразовано в значение типа «указатель на T». Результатом является указатель на функция.

3 голосов
/ 04 октября 2009

Для языковой разницы (сохраняются только объявления функций ниже, так как это то, что важно только)

void execute( void (&func)() );

void g();
int main() {
  void (*fp)() = g;
  execute(fp); // doesn't work
  execute(&g); // doesn't work either
  execute(g); // works
}

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

Для шаблонов это тоже имеет значение

template<typename T>
void execute(T &t) { T u = t; u(); }

template<typename T>
void execute(T t) { T u = t; u(); }

Эти двое сильно отличаются друг от друга. Если вы вызываете его с execute(g);, как описано выше, то первый попытается объявить функцию и инициализировать ее с t (ссылка на g). Сгенерированная функция будет выглядеть так:

void execute(void(&t)()) { void u() = t; u(); }

Теперь вы можете инициализировать ссылки и указатели на функции, но, конечно, не сами функции. Во втором определении T будет выведено к типу указателя функции путем вывода аргумента шаблона, и передача функции неявно преобразует его в этот тип параметра указателя. Так что все будет хорошо.


Я не знаю, почему MSVC трактует их по-разному для встраивания - но я также подозреваю, что это потому, что ссылки на функции появляются реже.

3 голосов
/ 04 октября 2009

Это не такая распространенная идиома, поэтому может случиться так, что команда VS не добавила правила для ее оптимизации.

0 голосов
/ 05 октября 2009

Разница между ссылкой (&) и указателем (*) заключается в том, что ссылка предоставляет адрес переменной или местоположения, а указатель указывает на местоположение в памяти адреса, сохраненного в нем.

int *pointer;
int variable;

pointer = &variable; // assigning the address of variable to pointer 

variable = 53;  // value of variable

cout << *pointer; // This should output the value of the address where is pointing, in this
                  //  case 53, that is the value of variable to where is pointing.

Мы можем сделать вывод, что (& variable) имеет адрес этой ячейки памяти, а * anyname указывает на адрес, хранящийся в ее памяти ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...