Данные прототипы:
void foo(int i);
void foo(int i, const std::string &s);
Реализация:
void foo(int i)
{
foo(i, std::string()) ;
//! ^^^^^^^^^^^^^ ^ here?
// nothing more.
}
//! ^ here?
void foo(int i, const std::string &s)
{
//do something
}
Где находится временный объект, созданный std::string()
выйти за рамки? Это хорошая практика для перегрузки функций таким образом?
Обновить:
Позвольте мне объяснить немного ситуации. В качестве упражнения я пытаюсь написать класс как std::vector
без использования шаблона. Единственный тип, который он держит std::string
, Тело класса можно найти в Другой вопрос.
При реализации resize()
функция-член, я обнаружил, что std::vector
Кажется, используют две функции:
void
resize(size_type __new_size);
void
resize(size_type __new_size, const value_type& __x);
Поэтому мне интересно, должен ли я использовать две функции вместо одной.
Я не думаю, что это плохая практика, особенно если вы делаете foo(int i)
в соответствии. Я могу придумать причину, когда это предпочтительнее: когда вы создаете указатели на функцию, если вы объявляете второй параметр по умолчанию, вы можете иметь только указатель на функцию, которая принимает 2 параметра.
Временное значение действует только как параметр для вызова функции.
inline void foo(int i)
{
foo(i, std::string());
}
void foo(int i, const std::string &s)
{
//do something
}
Нет, это не очень хорошая практика, по крайней мере, в этом конкретном случае. Используйте одну функцию и значение по умолчанию для аргумента, а не две функции, одна из которых, кажется, существует только для предоставления аргумента по умолчанию:
void foo(int i, const std::string &s = "")
{
//do something
}
Единственная «опасность» при прохождении временного const&
происходит, если функция создает объект, который переживает сам вызов функции, который хранит в себе const&
,
Думать
class A
{
const string& a;
public:
A(const string& a) :a(a) {}
void act() { .... /* use a */ }
};
A* foo(const string& s)
{ return new A(s); }
int main()
{
A* pa = foo(string());
//here, pa->act() will act on a dangling reference.
}
Если твой foo
функция просто использование строка, но не сохраняет ссылки для последующего использования, передача временного кода совершенно безопасна.
Если это происходит с использованием «загрузочной функции» или временного значения по умолчанию, это не имеет значения для результирующего кода.
На этом этапе использование одной или двух функций — это, скорее, вопрос стиля и возможности: сколько шансов у этих двух функций отличиться в ходе дальнейшего развития?
Если ответ «нет: вторая функция — просто определение (или ярлык) для очень частого случая», то значение по умолчанию отлично справляется со своей задачей.
Если ответ «давайте вернемся к другой функции ПО СЕЙЧАС, а позже уточним», тогда две функции предпочтительнее.
Однако значения по умолчанию НЕ являются шансом, если функция является шаблоном, и вы хотите, чтобы вывод типа работал:
template<class C, class T>
void fn(int i, basic_string<C,T>& s = ????);
Вы не можете использовать std :: string (), так как он не будет работать для C
Кроме как char
и не может использовать std::basic_string<C,T>()
так как это не позволит вывести, на fn(5)
позвоните, чтобы узнать, какие C и T должны быть.
Таким образом, вы в конечном итоге
void fn(int i) { fn(i,string()); }
.