Здесь представляет собой реализацию функции разрыва, которая доступна во многих других языках программирования в качестве стандартной функции:
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);
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.
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;
}
Используйте ссылки везде, где хотите, указатели, когда вы вынуждены.
Ссылки и указатели разделяют часть своей семантики: они являются псевдонимом для элемента, которого нет. Основное отличие заключается в управлении памятью: ссылки ясно выражают, что вы не несете ответственности за ресурс. С другой стороны, с указателями никогда не бывает ясно (если вы не имеете в виду интеллектуальные указатели): предполагается ли, что вы удалите указатель, или он будет удален извне?
Вы должны использовать указатели, когда вам нужно управлять памятью, хотите разрешить необязательную семантику или вам нужно изменить элемент, на который ссылаются позже.
В остальных случаях, когда вы можете использовать ссылку или указатель , ссылки более понятны, и им следует отдавать предпочтение.
Теперь, как вы отметили, они действительно не нужны:
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).
Я использую ссылки в аргументах функций не только для того, чтобы избежать копий, но и вместо указателей, чтобы избежать необходимости иметь дело с указателями NULL
там, где это необходимо. Указатели моделируют «может быть, есть значение, а может и нет ( NULL
)», ссылки являются четким заявлением о том, что значение требуется.
... и чтобы сделать его абсолютно ясным (-> комментарии ). Я стараюсь избегать указателей на модели «может быть, есть несколько значений» - вектор здесь лучший вариант. Указатели на несколько значений часто заканчиваются программированием в стиле C, потому что вам обычно также приходится передавать # элементов отдельно.
Используйте константную ссылку, чтобы дать имя значению, например:
const Vec3 &ba=b-a;
Это имя дает значение, но не обязательно создает для него переменную. Теоретически это дает компилятору больше свободы действий и может позволить ему избежать некоторых вызовов конструктора копирования.
(Связанный вопрос о переполнении стека без дублирования в Постоянная ссылка на временный . В ссылке Herb Sutter есть больше информацию об этом.)
Я склонен согласиться, но, возможно, возвращаемые значения const.
Аргумент копирующего конструктора ДОЛЖЕН передаваться как ссылка,
Что ж, у вас есть два варианта псевдонима для других значений (игнорирование 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]
}
Здесь контракт между вызывающим и вызываемым гарантирует, что возвращаемый тип всегда будет там. Вы можете безопасно вернуть ссылку и избежать некоторых вопросов, которые вызывают указатели.
Ссылки делают код красивее. Поэтому используйте их всякий раз, когда требуется ссылка, чтобы украсить ваш код.
Очевидный пример - потоковые операторы
std::ostream & operator<< (std::ostream &, MyClass const &...) {
....
}
mystream << myClassVariable;
Очевидно, вам не нужен указатель, поскольку проверка на NULL делает использование оператора очень утомительным iso удобным
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.
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