Когда передавать по ссылке, а когда по указателю в C ++? - PullRequest
44 голосов
/ 01 сентября 2010

Типичные ситуации:

  1. Передача std :: string в функцию foo (std :: string *) или foo (std :: string &);
  2. Передача tr1 ::shared_ptr для функции foo (tr1 :: shared_ptr * ptr) или foo (tr1 :: shared_ptr & ptr);

В общем, что является хорошей практикой.Я всегда путаюсь.Поначалу передача всего в качестве ссылок кажется согласованной, однако в Literals невозможно передать в качестве ссылок или NULL в качестве ссылок.

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

Считаете ли вы следующий фрагмент хорошим?

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <tr1/memory>
#include <algorithm>
using namespace std;
using namespace std::tr1;

int main(){
        map<string, shared_ptr<vector<string> > > adjacencyMap;
        vector<string>* myFriends = new vector<string>();
        myFriends->push_back(string("a"));
        myFriends->push_back(string("v"));
        myFriends->push_back(string("g"));
        adjacencyMap["s"] = shared_ptr<vector<string> >(myFriends);
        return 0;
}

Спасибо, Ajay

Ответы [ 8 ]

25 голосов
/ 01 сентября 2010

Ссылки легче получить правильно.

Ваша проблема с литералами в том, что вы не используете константные ссылки? Вы не можете привязать временный (созданный литералом) к неконстантной ссылке, потому что нет смысла менять его. Вы можете привязать один к константной ссылке.

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

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

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

23 голосов
/ 01 сентября 2010

Хорошее практическое правило: «Используйте ссылки, когда можете, и указатели, когда нужно».

6 голосов
/ 01 сентября 2010

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

  • передать по значению (для дешевого копирования объектов, все примитивы, типы с малыми значениями, std :: string , очень маленькие или пересчитанные строки)
  • передача по const ссылке (для доступа только для чтения к крупным объектам)
  • передача по указателю, если вам нужен доступ для чтения и записи

Если все следуют этим правилам, выМожно предположить, что параметры, передаваемые в функции, не изменяются, если не указан их адрес.Это сработало для нас.

5 голосов
/ 01 сентября 2010

Я действительно не понимаю, почему вы попали во все эти неприятности:

std::map < std::string, std::vector<std::string> > adjacencyMap;
std::vector<std::string>& sFriends = adjacencyMap["s"];
sFriends.push_back("a");
sFriends.push_back("v");
sFriends.push_back("g");

Почему вы тут вмешиваетесь shared_ptr?Ситуация, конечно, не требует этого!

3 голосов
/ 01 сентября 2010

Вероятно, не ответ на вопрос. Просто поцелуй.

int main()
{
        multimap<string, string> adjacencyMap;
        adjacencyMap.insert(std::make_pair("s", "a"));
        adjacencyMap.insert(std::make_pair("s", "v"));
        adjacencyMap.insert(std::make_pair("s", "g"));
        return 0;
}
2 голосов
/ 01 сентября 2010

Как правило, всегда старайтесь передавать параметры по ссылке на const.Передача указателей может привести к проблемам с владением, а также к множеству других возможностей для незначительных ошибок.

Какова цель NULL?Чтобы указать недопустимый указатель / объект.Если вы собираетесь передавать недопустимые объекты в функцию, то все, что вам нужно сделать, - это иметь метод для проверки правильности объекта.Как в:

void myfunc(const obj& myobj)
{
  if(myobj.valid())
    // DO SOMETHING
}

Примитивных типах, которые вы обычно хотите передавать по значению в любом случае, так как есть такие небольшие накладные расходы.И тогда вы все равно будете использовать литералы большую часть времени.Для строк вы должны попытаться использовать std::string и держаться подальше от const char* строк в стиле C как можно больше.Конечно, если вам нужно использовать C-строки, то у вас нет выбора, кроме как использовать указатели, но все ссылки должны быть подходящими.

Да, и чтобы быть действительно безопасным, старайтесь избегать исключенийthis:

vector<string>* myFriends = new vector<string>();
...
adjacencyMap["s"] = shared_ptr<vector<string> >(myFriends);

Вместо этого:

shared_ptr<vector<string> > myFriends(new vector<string>());

Просмотрите RAII и исключительную безопасность, чтобы узнать, почему это предпочтительный метод.

2 голосов
/ 01 сентября 2010

Вы можете просмотреть http://www.cplusplus.com/forum/beginner/3958/ для некоторых идей.Также полезно: http://www.velocityreviews.com/forums/t284603-pointers-vs-references-a-question-on-style.html

Наверное, нет "правильного" ответа.Вам необходимо взвесить все «за» и «против» каждого подхода с учетом конкретного контекста вашего проекта.

Я лично предпочитаю ссылки, но в любом случае рекомендую прочитать эти посты и размышлять об этом.

1 голос
/ 01 сентября 2010

Я бы предпочел

    map<string, shared_ptr<vector<string> > > adjacencyMap;
    shared_ptr<vector<string> > myFriends(new vector<string>());
    myFriends->push_back(string("a"));
    myFriends->push_back(string("v"));
    myFriends->push_back(string("g"));
    adjacencyMap["s"] = myFriends;
    return 0;

, поскольку это гарантирует, что ваша локальная обработка var безопасна для исключений.

Я действительно не вижу, как это обращается к вашему q, что было по существу в отношении ref против vs ptr. В обоих приведенных вами примерах я хотел бы использовать вторую (ref) форму.

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