Является ли хорошей практикой использование временных объектов в качестве аргументов при перегрузке функций?

Данные прототипы:

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);

Поэтому мне интересно, должен ли я использовать две функции вместо одной.

1

Решение

Я не думаю, что это плохая практика, особенно если вы делаете foo(int i) в соответствии. Я могу придумать причину, когда это предпочтительнее: когда вы создаете указатели на функцию, если вы объявляете второй параметр по умолчанию, вы можете иметь только указатель на функцию, которая принимает 2 параметра.

Временное значение действует только как параметр для вызова функции.

inline void foo(int i)
{
foo(i, std::string());
}

void foo(int i, const std::string &s)
{
//do something
}
2

Другие решения

Нет, это не очень хорошая практика, по крайней мере, в этом конкретном случае. Используйте одну функцию и значение по умолчанию для аргумента, а не две функции, одна из которых, кажется, существует только для предоставления аргумента по умолчанию:

void foo(int i, const std::string &s = "")
{
//do something
}
3

Единственная «опасность» при прохождении временного 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()); }

.

1
По вопросам рекламы [email protected]