объект — C ++ Модификация себя через Пропущенную Ссылку

Я полагаю, что это вопрос лучшей практики.

В C ++ у меня есть класс-оболочка для пути к файловой системе, похожая на os.path в Python. В этом классе-обертке есть функция-член под названием «Split», которая ищет последний встречающийся разделитель пути и разбивает его на «хвост» (последнюю часть пути) и «голову» (все остальное). В настоящее время функция использует свою собственную переменную-член m_filepath для разделения.

Некоторый код:

class FilePath {
public:
void Split(FilePath& head, FilePath& tail) const
{
FilePath h;
FilePath t;
//initialize h, t with portions of m_filepath...
head = h;
tail = t;
}
private:
std::string m_filepath;
};

int main(int argc, char ** argv)
{
FilePath some_path_1("/");
FilePath some_path_2("/home/");
some_path_1.Split(some_path_1, some_path_2);
return 0;
}

Когда я делаю что-то вроде этого, m_filepath файла some_path_1 будет перезаписываться независимо от того, какой «головой» оказался. Оператор const тоже не против.

Мой вопрос, каков наилучший способ справиться с этим? Бросить исключение? Разрешить перезапись объекта (это меня беспокоит и звучит небезопасно) и попросить разработчиков быть осторожнее? Умно ли использовать оператор возврата?

0

Решение

Большая проблема с написанием кода таким способом — это соблазн очистить код так, чтобы разделение выглядело так:

void Split(FilePath & h, FilePath & t) {
h.m_filepath = getHead(m_filepath);
t.m_filepath = getTail(m_filepath);
}

Но с тех пор h.m_filepath = ... на самом деле меняется this.m_filepath второй звонок не делает то, что ожидается. (Обратите внимание, что ваш код в настоящее время в порядке, но хрупок).

Корень (потенциальной) проблемы — это сочетание использования ссылок в качестве возвращаемых значений и необходимости нескольких возвращаемых значений. Но C ++ 11 поддерживает множественные возвращаемые значения через tie,

Так что я бы реализовать это как

class FilePath {
public:
std::pair<FilePath,FilePath> Split() const
{
FilePath h;
FilePath t;
//initialize h, t with portions of m_filepath...
head = h;
tail = t;
return std::make_pair(h,t);
}
private:
std::string m_filepath;
};

Тогда использование будет выглядеть так:

int main(int argc, char ** argv)
{
FilePath some_path_1("/");
FilePath some_path_2("/home/");
std::tie(some_path_1, some_path_2) = some_path_1.Split();
return 0;
}

И довольно ясно, что some_path_1 а также some_path_2 обновят их значения, и вам не нужно беспокоиться, что запись в аргументы изменит это, так как аргументов больше нет.

1

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

редактировать Ах! Я только что понял, что ты хотел Split() делать: сплит this в head а также tail — и надеюсь, что они не пройдут this в любой head ни tail,

В другом сценарии operator =(Class &rhs) Лучше всего сначала сравнить &rhs против this чтобы избежать этой точной проблемы — но я не думаю, что у вас есть эта проблема в любом случае. При использовании, которое вы дали, не только ясно, что произойдет, ваша реализация достаточно хороша, чтобы позволить этому случиться. Я бы не волновался (как сказал @MM).


Когда у вас есть функция-член, ожидается, что функция будет работать с экземпляром класса: Split() или выключи какую-то информацию о себе.

То, что вы хотите, это static функция-член: функция, которая, хотя и связана с ее классом, не работает с предполагаемым this, Сделать Split() функция static:

static void Split(...); // Note no concept of const required - no `this` to modify!

и назовите это так:

FilePath::Split(some_path_1, some_path_2);

Или вы можете сделать так, чтобы Split() возвращает хвост и изменяет себя, чтобы быть просто головой:

FilePath Split();

Но в этом случае немного неясно, в каком направлении происходит раскол. Как насчет:

FilePath SplitHead();

FilePath SplitTail();

Эти два последних могут быть реализованы с точки зрения static Метод выше, вот так:

FilePath FilePath::SplitHead() {
FilePath head = *this;
Split(head, *this);
return head;
} // FilePath::SplitHead()

FilePath FilePath::SplitTail() {
FilePath tail;
Split(*this, tail);
return tail;
} // FilePath::SplitTail()
0

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