ТАК много вопросов (прямых и косвенных) втиснуто в такое маленькое пространство!
В чем разница между Foo
и Bar
.
vector<Line*> Foo;
vector<Line*>* Bar = new vector<Line*>();
Foo
является объектом автоматического (потенциально статического (но здесь не важного различия)) срока хранения. Это означает, что он создается в точке объявления (вызываемые конструкторы) и уничтожается при выходе из области видимости (вызываемые деструкторы).
Bar
с другой стороны, это указатель. Указатель не имеет конструкторов или деструкторов и используется для point
в других объектах (или NULL). Здесь Bar
инициализируется так, чтобы указывать на объект динамического хранения. Это объект, который необходимо разблокировать вручную (в противном случае он будет вытекать).
особенно при передаче Foo
и Bar
между функциями?
При передаче Foo
(по значению) в / из функций конструктор копирования используется для создания копии исходного объекта. Примечание. В стандарте прямо указано, что копирование из функции (с помощью возврата) может быть исключено (см. RVO / NRVO), и все современные компиляторы удаляют дополнительную конструкцию копирования и создают ее на месте возврата (но это невидимая оптимизация для пользователя просто думать об этом как очень эффективная копия из функции). Результатом этого является то, что при передаче в функцию (по значению) или возвращении из функции (по возврату) вы работаете с новым объектом (а не с оригиналом). Это важно, поскольку побочные эффекты от использования объекта не повлияют на оригинал. (см. ваш вопрос ниже о возвращении Foo
).
При передаче Bar
(по значению) указатель копируется. Но это означает, что то, на что указывают, то же самое. Таким образом, изменение объекта с помощью указателя - это изменение исходного значения. Это делает передачу его в качестве параметра очень дешевой (потому что все, что вы передаете, это адрес объекта). Но это делает возвращение значения потенциально опасным, потому что вы можете вернуть адрес объекта, который вышел из области видимости внутри функции.
Использование указателей в опасных по своей природе и современных программах на C ++ редко использует RAW-указатели напрямую. Указатели обычно заключаются в объекты, которые управляют владением и потенциальной продолжительностью жизни объекта (см. Интеллектуальные указатели и контейнеры).
Когда было бы безопасно вызывать delete на панели, если вообще?
Безопасно удалять Bar
только если:
- НУЛЬ
- Объект, на который он указывает, был динамически распределен через new.
Полагаю, никогда не безопасно вызывать delete
на Bar
, если все в этом векторе не было перемещено?
Безопасно было бы удалить Bar
, даже если его содержимое не было перемещено (хотя вы можете утечь, если содержащиеся в нем указатели принадлежат Bar
(это не является небезопасным, но может быть неудобно, когда вы исчерпываете пространство )). Это еще одна причина, по которой указатели редко используются напрямую, семантика владения, связанная с указателем, отсутствует. Это означает, что мы не можем сказать, владеет ли Bar
указателями, которые он содержит (владелец обязан вызывать delete для указателя, когда он больше не используется).
Если я верну Foo
, не будет ли он (и его содержимое) удален при выходе из функции?
Да. Но поскольку вы возвращаете объект, он будет скопирован из функции. То, что вы используете вне функции - это копия Foo
(хотя оптимизаторы могут исключить копию из-за RVO / NRVO. Нет, если копия исключена, деструктор также исключается).
Похоже, допустим, у меня есть функция: query и expressionParser:
vector<Line *> BSTIndex::query(string expression)
{
vector<Line *> result; //Holds the lines that match the expression
string query = expression;
queue<string> * output = expressionParser(query);
doSomeStuffWithOutputHere();
return result;
}
queue<string> * BSTIndex::expressionParser(string query)
{
char* cQuery = new char[100];
strcpy_s(cQuery, 100,query.c_str());
queue<string> * output = new queue<string>(); //Operators go in the queue
stack<string> * s = new stack<string>(); //Operands go on the stack
performSomeMagicOnQueueAndStackHere();
return output;
}
Стек на самом деле является только локальным для expressionParser, поэтому я ЗНАЮ, что могу удалить из него новое ключевое слово.
Не только вы, но и вы должны. Как и сейчас, вы вытекаете из объекта, когда он выходит из области видимости.
Очередь, однако, должна вернуться к функции запроса, где она используется, но тогда это все.Должен ли я создать указатель на очередь в этом случае (я хочу сказать «да», потому что он выйдет из области видимости, когда expressionParser вернется).
Нет.Вы можете передать объект обратно по значению.Он будет правильно скопирован из функции.Если вы обнаружите, что это дорого (маловероятно), вы можете создать динамический объект с новым и передать его обратно в качестве указателя (но вы можете захотеть взглянуть на умные указатели).Помните, что указатели не указывают на то, что вы являетесь владельцем, поэтому неясно, кто должен удалить указатель (или даже если он должен быть удален).Поэтому (если передача значения слишком дорогая), используйте std :: auto_ptr <> и передайте указатель обратно внутрь него.
Если мне нужно создать указатель, то я должен вызвать вывод удаленияв моей функции запроса, чтобы правильно избавиться от очереди?
Да.И нет. Если вы создаете dynamic object
с новым.Тогда кто-то должен вызвать удаление на этом.Это плохой стиль C ++, чтобы делать это вручную.Научитесь использовать умные указатели, чтобы это делалось автоматически и в безопасном особняке исключений.
Мое последнее беспокойство - вектор, возвращаемый запросом.Должно ли это быть так, как у меня, или это указатель и в чем разница между ними?
Я бы сделал это так:
vector<Line> BSTIndex::query(string const& expression)
{
vector<Line> result; // 1 Keep line objects not pointers.
queue<string> output = expressionParser(expression);
doSomeStuffWithOutputHere();
return result;
}
queue<string> BSTIndex::expressionParser(string const& query)
{
char cQuery[100]; // Don't dynamically allocate
// unless somebody takes ownership.
// It would probably be better to use string or vector
// depending on what you want to do.
strcpy_s(cQuery, 100, query.c_str()); // std::string can use the assignment operator.
queue<string> output; // Just build the que and use it.
stack<string> s; // Unless there is a need. Just use a local one.
performSomeMagicOnQueueAndStackHere();
return output;
}
Один разЯ использую этот вектор (отображаю информацию в нем), мне нужно, чтобы он был удален из памяти, однако указатели, содержащиеся в векторе, все еще хороши, и элементы, на которые они указывают, не должны быть удалены.Каков наилучший подход в этом случае?
Зависит от того, кто владеет указателями.
Что происходит с содержимым контейнеров, когда вы вызываете delete для контейнера?
Если содержимое контейнеров является указателями.Тогда ничего.Указатели исчезают (то, на что они указывают, остается неизменным и неизменным).Если контейнер содержит объекты (не указатели), то для объектов вызывается деструктор.
Если контейнер содержит указатели, и эти указатели удаляются, не повлияет ли это на другие области моей программы?
Было бы.Но вам придется вызвать удаление вручную.