Праматерия класс


В нашем производственном коде, мы не можем использовать boost или C++0х. Форматирование строк с помощью функции sprintf или stringstream раздражает в данном случае, и это побудило меня написать мой собственный маленький праматерии класс. Мне любопытно, если реализация данного класса или использовать его, вводит любое неопределенное поведение.

В частности, эта линия полностью определены:

Reject( Formatter() << "Error Recieved" << 42 << " " << some_code << " '" << some_msg << "'");

Я считаю, что это нормально, но я хотел рецензирования.

Три главных проблемных моментов:

  1. Есть двойное назначение в одну точку последовательности? Это УБ?
  2. У меня проблемы со временем жизни Вэнс?
  3. Мой форматтер класса (или назначению его) вводить любые УБ?

В праматерии класс имеет как (templatized) оператор<< и оператор СТД::строка. Намерение состоит в том, чтобы использовать средства форматирования() класса в качестве временного на месте СТД::строка параметр для любой функции принимает константный СТД::строка&.

Вот определение класса:

class Formatter
{
public:
 Formatter() {};
 template<class Field> Formatter& operator<<(Field f)
 {
  ss_ << f;
  return *this;
 }
 operator std::string() const { return ss_.str(); }
private:
 std::stringstream ss_;
};

И вот полный теста, в том числе указанное выше определение. Вы должны быть в состоянии скомпилировать и запустить как есть. Вы видите какие-то УБ?

#include <cstdlib>
#include <string>
#include <sstream>
#include <iostream>

class Formatter
{
public:
 Formatter() {};
 template<class Field> Formatter& operator<<(Field f)
 {
  ss_ << f;
  return *this;
 }
 operator std::string() const { return ss_.str(); }
private:
 std::stringstream ss_;
};

void Reject(const std::string& msg)
{
 std::cout << "Recieved Message: '" << msg << "'" << std::endl;
}

int main()
{
 const char& some_code = 'A';
 const char* some_msg = "Something";

 Reject( Formatter() << "Error Recieved" << 42 << " " << some_code << " '" << some_msg << "'");
}


1632
25
задан 26 января 2011 в 09:01 Источник Поделиться
Комментарии
6 ответов

В дополнение к тому, что уже сказано, я бы:


  • Марк stringstream как общественные. Это не влияет на большинство использует ваш код, и уже могут быть взломаны с Заказ манипулятора к вам на "внутренней" потоковый объект, но это позволит тем, кто нуждается, чтобы получить доступ к внутреннему потоку (например, чтобы избежать копировать строки, присущие stringstream интерфейс), и знаем специфику их реализации, которые позволяют, что они хотят, чтобы сделать так. Конечно, 0х семантику перемещения развеять большую часть этой необходимости, но до сих пор не совсем еще здесь™.

  • Проверить поток, прежде чем возвращать строку; если он находится в неисправном состоянии, исключение (или, по крайней мере, войти в состояние где-то до возвращения строку). Это маловероятно для большинства применений, но если это произойдет, вы будете рады, что вы нашли на поток не удалось, а не винт с форматированием, а интересно, почему "это не работает".

Что касается двойного назначения, нет присвоения. Точки последовательности должны быть в основном то, что люди ожидают, но, точно, похоже:

some_function(((Formatter() << expr_a) << expr_b) << expr_c);
// 1 2 3

Порядок операторов, как будто это была функция звонков, так что:


  • Праматерия() и expr_a оба происходят до вставки обозначены 1.

  • Вышеперечисленное, плюс вставки 1, плюс expr_b произойдет до вставки 2.

  • Вышеперечисленное, плюс вставки 2, плюс expr_c произойдет до вставки 3.

  • Обратите внимание, это только ограничивает в одном направлении: expr_c может произойти после expr_a и до форматирования(), например.

  • Естественно, все вышеперечисленное плюс преобразование строк происходит до вызова some_function.

Чтобы добавить в обсуждение Вэнс, все создания временных объектов в выражении:

some_function(Formatter() << make_a_temp() << "etc.")
// one temp another temp and so on

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

Для того, чтобы обрабатывать все манипуляторы, такие как std::епси, добавить:

struct Formatter {
Formatter& operator<<(std::ios_base& (*manip)(std::ios_base&)) {
ss_ << manip;
return *this;
}
Formatter& operator<<(std::ios& (*manip)(std::ios&)) {
ss_ << manip;
return *this;
}
Formatter& operator<<(std::ostream& (*manip)(std::ostream&)) {
ss_ << manip;
return *this;
}
};

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

9
ответ дан 27 января 2011 в 08:01 Источник Поделиться

Только три замечания:


  1. Я хотел бы удалить пустой конструктор.

  2. Насчет обработки СТД::манипуляторы?

  3. Разве вы не хотите передать значения полей по константной ссылке?

.

 template<class Field> Formatter& operator<<(Field const& f)
// ^^^^^^

Ваши опасения:



  1. Есть двойное назначение в одну точку последовательности? Это УБ?


Не вижу ни одного.
Выглядит хорошо.



  1. У меня проблемы со временем жизни Вэнс?


Нет. Не думаю, что так.

6
ответ дан 27 января 2011 в 01:01 Источник Поделиться

Я думаю, что вы можете быть обеспокоены вопросами временной жизни. (Я знаю, что на основе подобного кода.)

Временный объект, созданный в качестве параметра для отклонения придется всю жизнь привязан к выражению оно создано. (Это в стандарта C++ где-то.) Так что даже с вашим операторы преобразования возвращают значения, все они будут уничтожены после выражения, которое содержит отклонить.

5
ответ дан 26 января 2011 в 10:01 Источник Поделиться


  • Я бы использовать с std::ostringstream , потому что вы не используете (по-видимому, нужно) форматирование возможностей и std::istringstream.

  • Что происходит при форматировании не выполняется? Вы можете проверить для отказа?

5
ответ дан 27 января 2011 в 03:01 Источник Поделиться

Выглядит нормально. Не беспокойтесь слишком много и в конечном итоге-технических простое решение :)

Редактировать:

На самом деле, я хотел бы сделать параметры оператора<< в константные ссылки.

4
ответ дан 26 января 2011 в 10:01 Источник Поделиться

Выглядит нормально. Пустой конструктор нужно, компилятор автоматически будет делать только штрафом. "Принял" должно быть написано "получил" :)

4
ответ дан 26 января 2011 в 10:01 Источник Поделиться