Все в C++ по умолчанию передается по значению
В C++ все типы передаются по значению, если они не идут с &
или же *
условное обозначение?
Например, в Java передача массива в качестве аргумента функции будет по умолчанию передаваться по ссылке. C++ дает вам больше контроля над этим?
РЕДАКТИРОВАТЬ: Спасибо за все ваши ответы, я думаю, что я понимаю, что все значение по передаче более ясно. Для тех, кто все еще не понимает, как Java передается по значению (копия ссылки на объект), этот ответ действительно прояснил его для меня.
2 ответа
В C++ все типы передаются по значению, если они не идут с символом & или *?
Нет, если вы передаете что-то как * параметр (его указатель), это все равно передается по значению. Копия переданного указателя сделана. Но и оригинал, и копия указывают на одну и ту же память. Это аналогичная концепция в C# - я верю и в Java, просто вы не используете * там.
Вот почему, если вы вносите изменения во внешние объекты с помощью этого указателя (например, с помощью разыменования), изменения также будут видны в исходном объекте.
Но если вы просто скажете назначить новое значение указателю, с внешним объектом ничего не произойдет. например
void foo(int* ptr)
{
// ...
// Below, nothing happens to original object to which ptr was
// pointing, before function call, just ptr - the copy of original pointer -
// now points to a different object
ptr = &someObj;
// ...
}
Например, в Java передача массива в качестве аргумента функции будет по умолчанию передаваться по ссылке. C++ дает вам больше контроля над этим?
В C++ или C, если вы передаете массив (например, int arr[]
), то, что передается, обрабатывается как указатель на первый элемент массива. Следовательно, то, что я сказал выше, верно и в этом случае.
О & вы правы. Вы можете даже применить & к указателям (например, int *&
), и в этом случае указатель действительно передается по ссылке - копия не создается.
Вероятно, касательно вашего вопроса, но я часто выбираю другое направление, чтобы понять, что происходит, когда вы вызываете функцию в C++.
Разница между
void foo(Bar bar); // [1]
void foo(Bar& bar); // [2]
void foo(Bar* bar); // [3]
это тело в [1]
получит копию оригинальной панели (мы называем это по значению, но я предпочитаю думать о ней как о своей собственной копии).
Тело [2]
будет работать с точно таким же bar
объект; нет копий. Можем ли мы изменить это bar
Объект зависит от того, был ли аргумент Bar& bar
(как показано на рисунке) или const Bar& bar
, Обратите внимание, что в правильно сформированной программе[2]
всегда получит объект (нет null
Рекомендации; давайте оставим висячие ссылки в стороне).
Тело [3]
получит копию указателя на оригинал bar
, Могу ли я изменить указатель и / или указываемый объект, зависит от того, был ли аргумент const Bar* bar
, const Bar* const bar
, Bar* const bar
, или же Bar* bar
(Да, действительно). Указатель может или не может быть null
,
Причина, по которой я делаю это умственное различие, состоит в том, что копия объекта может иметь или не иметь ссылочную семантику. Например: копия экземпляра этого класса:
struct Foo {
std::shared_ptr<FooImpl> m_pimpl;
};
по умолчанию будет иметь то же "содержимое", что и исходный (новый общий указатель, указывающий на то же FooImpl
указатель). Это, конечно, зависит от того, как программист спроектировал класс.
По этой причине я предпочитаю думать о [1]
как "берет копию бара", и если мне нужно узнать, будет ли такая копия тем, что я хочу и что мне нужно, я пойду и изучу класс напрямую, чтобы понять, что именно этот класс означает в частности под копией.