Рекомендованный тип ссылки C ++

Здесь представляет собой реализацию функции разрыва, которая доступна во многих других языках программирования в качестве стандартной функции:

type 
  TStringDynArray = array of String;

function Explode(const Separator, S: string; Limit: Integer = 0): TStringDynArray; 
var 
  SepLen: Integer; 
  F, P: PChar; 
  ALen, Index: Integer; 
begin 
  SetLength(Result, 0); 
  if (S = '') or (Limit < 0) then Exit; 
  if Separator = '' then 
  begin 
    SetLength(Result, 1); 
    Result[0] := S; 
    Exit; 
  end; 
  SepLen := Length(Separator); 
  ALen := Limit; 
  SetLength(Result, ALen); 

  Index := 0; 
  P := PChar(S); 
  while P^ <> #0 do 
  begin 
    F := P; 
    P := AnsiStrPos(P, PChar(Separator)); 
    if (P = nil) or ((Limit > 0) and (Index = Limit - 1)) then P := StrEnd(F); 
    if Index >= ALen then 
    begin 
      Inc(ALen, 5); 
      SetLength(Result, ALen); 
    end; 
    SetString(Result[Index], F, P - F); 
    Inc(Index); 
    if P^ <> #0 then Inc(P, SepLen); 
  end; 
  if Index < ALen then SetLength(Result, Index); 
end; 

Пример использования:

var
  res: TStringDynArray;
begin
  res := Explode(':', yourString);

13
задан BradleyDotNET 16 September 2014 в 23:01
поделиться

13 ответов

As a return value of an opaque collection accessor/mutator

The operator[] of std::map returns a reference.


To shorten the text needed to reference a variable

If you miss old-school with Foo do ... statement (that's Pascal syntax), you can write

 MyString &name = a->very->long_->accessor->to->member;
 if (name.upcase() == "JOHN") {
    name += " Smith";
 }

another example of this can be found in Mike Dunlavey's answer


To state that something is just a reference

References are also useful in wrapper objects and functors--i.e. in intermediate objects that logically contact no members but only references to them.

Example:

class User_Filter{
  std::list<User> const& stop_list;
  public: Functor (std::list<User> const& lst)
    : stop_list(lst) { }
  public: bool operator()(User const& u) const
    {  return stop_list.exists(u); }
};

find_if(x.begin(),x.end(),User_Filter(user_list));

The idea here that it's a compile error if you don't initialize a reference in constructor of such an object. The more checks in compile time--the better programs are.

16
ответ дан 1 December 2019 в 17:34
поделиться

Here's a case where it's handy:

MyClass myArray[N];

for (int i = 0; i < N; i++){
    MyClass& a = myArray[i];
    // in code here, use a instead of myArray[i], i.e.
    a.Member = Value;
}
11
ответ дан 1 December 2019 в 17:34
поделиться

Используйте ссылки везде, где хотите, указатели, когда вы вынуждены.

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

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

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

Теперь, как вы отметили, они действительно не нужны:

8
ответ дан 1 December 2019 в 17:34
поделиться

I tend to use reference members instead of pointers for externally controlled non-optional construction parameters.

EDIT (added example):

Let's say that you have a database and a DAO class having the database as a dependency:

struct Database {};
struct PersonDao {
    const Database &m_d;
    PersonDao(const Database &d): m_d(d) {}
};

Furthermore, the scope of the database is controlled externally from the DAO:

int main() {
    Database d;
    PersonDao pd(d);
}   

In this case it makes sense to use a reference type, since you don't ever want DAO::m_d to be null, and its lifetime is controlled externally (from the main function in this case).

5
ответ дан 1 December 2019 в 17:34
поделиться

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

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

3
ответ дан 1 December 2019 в 17:34
поделиться

Используйте константную ссылку, чтобы дать имя значению, например:

const Vec3 &ba=b-a;

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

(Связанный вопрос о переполнении стека без дублирования в Постоянная ссылка на временный . В ссылке Herb Sutter есть больше информацию об этом.)

3
ответ дан 1 December 2019 в 17:34
поделиться

Я склонен согласиться, но, возможно, возвращаемые значения const.

1
ответ дан 1 December 2019 в 17:34
поделиться

Аргумент копирующего конструктора ДОЛЖЕН передаваться как ссылка,

3
ответ дан 1 December 2019 в 17:34
поделиться

Что ж, у вас есть два варианта псевдонима для других значений (игнорирование shared_ptrs и т.п.): указатели и ссылки.

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

Возможно, что более важно, ссылки можно использовать, не задумываясь обо всех проблемах, которые возникают с указателями. Это, наверное, главное преимущество. Семантически ссылка - это вещь. Если как вызывающий / вызываемый вы гарантируете, что базовая память не исчезнет, ​​вам не нужно вводить пользователя в заблуждение какими-либо вопросами, которые приходят вместе с указателями (нужно ли мне это освобождать? Может ли это быть NULL? и т.д.) и может безопасно использовать ссылку для удобства.

Примером этого может быть функция, которая ищет соответствующую строку для перечисления,

const std::string& ConvertToString( someEnum val)
{
   static std::vector< std::string > lookupTable;
   if (lookupTable.empty())
   {
      // fill in lookup table
   }
   // ignoring the cast that would need to happen
   return lookupTable[val]
}

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

я должен сбивать пользователя с толку любыми вопросами, которые приходят вместе с указателями (нужно ли мне освобождать это? Может ли это быть NULL? и т. д.), и можно безопасно использовать ссылку для удобства.

Примером этого может быть функция, которая ищет соответствующую строку для перечисления,

const std::string& ConvertToString( someEnum val)
{
   static std::vector< std::string > lookupTable;
   if (lookupTable.empty())
   {
      // fill in lookup table
   }
   // ignoring the cast that would need to happen
   return lookupTable[val]
}

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

я должен сбивать пользователя с толку любыми вопросами, которые приходят вместе с указателями (нужно ли мне освобождать это? Может ли это быть NULL? и т. д.), и можно безопасно использовать ссылку для удобства.

Примером этого может быть функция, которая ищет соответствующую строку для перечисления,

const std::string& ConvertToString( someEnum val)
{
   static std::vector< std::string > lookupTable;
   if (lookupTable.empty())
   {
      // fill in lookup table
   }
   // ignoring the cast that would need to happen
   return lookupTable[val]
}

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

1
ответ дан 1 December 2019 в 17:34
поделиться

Ссылки делают код красивее. Поэтому используйте их всякий раз, когда требуется ссылка, чтобы украсить ваш код.

1
ответ дан 1 December 2019 в 17:34
поделиться

Очевидный пример - потоковые операторы

std::ostream & operator<< (std::ostream &, MyClass const &...) {
  ....
}

mystream << myClassVariable;

Очевидно, вам не нужен указатель, поскольку проверка на NULL делает использование оператора очень утомительным iso удобным

1
ответ дан 1 December 2019 в 17:34
поделиться

I've used a reference to an ostream instead of a pointer. I supppose that I prefer references to pointers when the class has a lot of operators.

0
ответ дан 1 December 2019 в 17:34
поделиться

i would like to enlist some cases:

1) while writing singleton classes

 class singleton
    {
        singleton();
        explicit singleton(const singleton&);
        singleton& operator=(const singleton&);
    public:
        static singleton& instance()
        {
            static singleton inst;
            return inst;
        }
    };// this is called the 'Meyers' singleton pattern. refer to More Effective C++ by  Scott Meyers

it has all the benefits, but avoids using the new operator

**2)**here is no such thing as a null reference. A reference must always refer to some object. As a result, if you have a variable whose purpose is to refer to another object, but it is possible that there might not be an object to refer to, you should make the variable a pointer, because then you can set it to null. On the other hand, if the variable must always refer to an object, i.e., if your design does not allow for the possibility that the variable is null, you should probably make the variable a reference

**3)**Because a reference must refer to an object, C++ requires that references be initialized:

  string& rs;             // error! References must
                          // be initialized

  string s("xyzzy");

  string& rs = s;         // okay, rs refers to s

Pointers are subject to no such restriction

The fact that there is no such thing as a null reference implies that it can be more efficient to use references than to use pointers. That's because there's no need to test the validity of a reference before using it

**4)**Another important difference between pointers and references is that pointers may be reassigned to refer to different objects. A reference, however, always refers to the object with which it is initialized: ¤ Item M1, P10

  string s1("Nancy");
  string s2("Clancy");

  string& rs = s1;         // rs refers to s1

  string *ps = &s1;        // ps points to s1

  rs = s2;                 // rs still refers to s1,
                           // but s1's value is now
                           // "Clancy"

  ps = &s2;                // ps now points to s2;
                           // s1 is unchanged
0
ответ дан 1 December 2019 в 17:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: