Разве указатель не является ссылкой, если вы не разыменовали его? - PullRequest
5 голосов
/ 24 февраля 2010

Разве указатель не является просто ссылкой, если вы не отменяете ссылку на него?

#include "stdafx.h"
#define BOOST_TEST_MODULE example
#include <boost/test/included/unit_test.hpp>


std::list<int>* user_defined_func( ) {
    std::cout << "BEGIN: user_defined_func" << std::endl;
    std::list<int>* l = new std::list<int>;

    l->push_back(8);
    l->push_back(0);

    std::cout << "END: user_defined_func" << std::endl;

    return l;
}


bool validate_list(std::list<int> &L1)
{

   std::cout << "BEGIN: validate_list" << std::endl;

   std::list<int>::iterator it1 = L1.begin();

   for(; it1 != L1.end(); ++it1)
   {
      if(*it1<= 1){

         std::cout << "Validation failed because an item in the list was less than or equal to 1." << std::endl;
         std::cout << "END: validate_list" << std::endl;
         return false;
       }
   }

   std::cout << "Test passed because all of the items in the list were greater than or equal to 1" << std::endl;
   std::cout << "END: validate_list" << std::endl;
  return true;
}

BOOST_AUTO_TEST_SUITE( test )
BOOST_AUTO_TEST_CASE( test )
{
   std::list<int>* list1 = user_defined_func();
   BOOST_CHECK_PREDICATE( validate_list, (list1) );
}
BOOST_AUTO_TEST_SUITE_END()

В строке

BOOST_CHECK_PREDICATE( validate_list, (list1) ); 

выше, мне сказали, что я не могу передать указатель на функцию, ожидающую ссылку. Я думал, что указатель (который не был разыменован) был просто адресом (то есть ссылкой). Что мне здесь не хватает?

Ответы [ 5 ]

13 голосов
/ 24 февраля 2010

Указатели и ссылки похожи, но различаются несколькими способами:

  1. У них другой синтаксис доступа. Если у вас есть T* a и T& b, вы получаете доступ к переменным-членам и функциям, используя a->member и b.member соответственно.
  2. Указатели могут указывать ни на что, а ссылки всегда должны указывать на что-то. a = 0 является законным, но b = 0 или что-либо на этот счет не является.
  3. Указатели могут быть «переустановлены» (то есть, указатель может быть изменен), тогда как ссылки не могут. a = &b допустимо, но int c; b = c; нет (однако T& b = c - ссылки могут быть установлены только при их инициализации). (Спасибо Майк Д.)
  4. Указатели не могут ссылаться на временные ссылки, но const ссылки могут.
  5. Указатели могут указывать на другие указатели (T**), но ссылки не могут ссылаться на другие ссылки (т. Е. Нет такой вещи, как T&&, хотя обратите внимание, что C ++ 0x будет использовать T&& для определения семантики перемещения ). В результате вы не можете иметь массивы ссылок. (Спасибо AshleysBrain)

Можно задаться вопросом, почему у нас вообще есть ссылки, а не просто постоянно использовать указатели (как в C). Причина в перегрузке операторов или определенных операторах.

Рассмотрим оператор присваивания. Какой будет синтаксис функции без ссылок? Если бы это было T* operator=(T* lhs, T rhs), то мы должны были бы написать что-то вроде:

int a(1);
&a = 2;

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

6 голосов
/ 24 февраля 2010

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

4 голосов
/ 24 февраля 2010

Разве указатель не является ссылкой, когда Вы не отменяете это?

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

Ссылка - это псевдоним, еще один способ ссылки на существующее значение.

int i = 5;
int* p = &i; // The value in p is the address that i is stored at.
int& r = i;  // The value in r is 5, because r is an alias of i.
             //   Whenever you use r, it's as if you typed i, and vice versa.
             //   (In this scope, anyway).

int sum = i + r; // Identical to i + i or r + i or r + r.

Edit:

, поскольку list1 является указателем, как мне получить доступ к ссылке ...?

У вас есть два варианта. Вы можете разыменовать указатель, чтобы попасть в список, на который он указывает:

std::list<int>* list1 = user_defined_func();
std::list<int>& list1ref = *list1;
BOOST_CHECK_PREDICATE( validate_list, list1ref );
delete list1;

Конечно, это можно сократить до:

std::list<int>* list1 = user_defined_func();
BOOST_CHECK_PREDICATE( validate_list, *list1 );
delete list1;

Ваша функция проверки может взять указатель вместо ссылки (не забудьте изменить L1. {Что-то} на L1 -> {что-то}):

bool validate_list(std::list<int>* L1) { ... }
2 голосов
/ 24 февраля 2010

Я бы сказал, что ссылка больше похожа на обработчик указателя.

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

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

чтобы ваш код работал, вам нужно сделать

BOOST_CHECK_PREDICATE( validate_list, (*list1) );

но я уверен, что вы уже знали, что:)

Я думаю, что этот вопрос и ответ совпадают В чем различия между переменной указателя и ссылочной переменной в C ++?

1 голос
/ 24 февраля 2010

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

  1. Ссылки должны быть связаны во время инициализации и не могут быть повторно связаны для ссылки на другой объект, в то время как указатели могут указывать на разные адреса в разное время.
  2. Указатели могут быть NULL, но ссылки всегда должны быть связаны с объектом.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...