Я бы не использовал ни один из подходов.
В этом контексте, похоже, цель foo () - обрабатывать вектор. То есть работа foo () заключается в обработке вектора.
Но во второй версии foo () неявно дано второе задание: создать вектор. Семантика между foo () версии 1 и foo () версии 2 не одинакова.
Вместо того, чтобы делать это, я бы рассмотрел наличие только одной функции foo () для обработки вектора и другой функции, которая создает вектор, если вам нужна такая вещь.
Например:
void foo(int i, const std::vector<int>& optional) {
// process vector
}
std::vector<int>* makeVector() {
return new std::vector<int>;
}
Очевидно, что эти функции тривиальны, и если все, что нужно сделать makeVector () для выполнения своей работы, это просто вызов new, то, возможно, нет смысла иметь функцию makeVector (). Но я уверен, что в вашей реальной ситуации эти функции делают намного больше, чем показано здесь, и мой код выше иллюстрирует фундаментальный подход к семантическому дизайну: дает одной функции одну работу для выполнения .
Схема, которую я описал выше для функции foo (), также иллюстрирует еще один фундаментальный подход, который я лично использую в своем коде, когда речь идет о разработке интерфейсов, который включает сигнатуры функций, классы и т. Д. Вот что: я считаю, что хороший интерфейс: 1) прост и интуитивно понятен в использовании правильно, и 2) трудно или невозможно использовать неправильно . В случае функции foo () мы косвенно говорим, что при моем дизайне вектор должен существовать и быть «готовым». Сконструировав функцию foo (), чтобы она брала ссылку вместо указателя, интуитивно понятно, что вызывающая сторона должна уже иметь вектор, и им будет трудно передать что-то, что не является готовым вектором .