Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Renji
2123 / 1482 / 452
Регистрация: 05.06.2014
Сообщений: 4,320
#1

Внутреннее устройство потоков - C++

29.09.2015, 04:23. Просмотров 606. Ответов 17
Метки нет (Все метки)

Очень тупой вопрос - почему std::ios хранит в своих потрохах указатель на объект std::streambuf, а не является потомком std::streambuf? Принимая во внимание что std::streambuf все равно собран на виртуальных функциях, а значит поведение std::ios один фиг в итоге задается через перегрузку этих самых виртуальных функций.
http://www.cyberforum.ru/cpp-beginners/thread1335941.html
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
29.09.2015, 04:23
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Внутреннее устройство потоков (C++):

Создание и завершение процессов и потоков. Приоритеты выполнения потоков
Здравствуйте. Буду очень раз если поможете понять,что конкретно нужно сделать в...

Внутреннее представление числа в памяти
нужно сделать реализацию числа в памятиfloat d1 = 72.9e-8;... а как??? это...

Внутреннее представление конструтора и деструктора
Я знаю, что конструктор и деструктор в явном виде ничего не возвращает. Однако...

Разное определение(внутреннее) виртульных функций
Мне вот интересно внутренность виртуальной функции должно повторятся или нет....

Внутреннее хранение данных для обработки
Привет! Снова вопрос больше теоретический. Начал писать консольную программу...

17
Ilot
Эксперт С++
1826 / 1184 / 342
Регистрация: 16.05.2013
Сообщений: 3,119
Записей в блоге: 5
Завершенные тесты: 1
29.09.2015, 07:44 #2
Цитата Сообщение от Renji Посмотреть сообщение
Очень тупой вопрос - почему std::ios хранит в своих потрохах указатель на объект std::streambuf, а не является потомком std::streambuf?
Потому что назначение std::ios выполнять форматирование ввода/вывода, а std::streambuf читать/писать из/в устройства.
0
Renji
2123 / 1482 / 452
Регистрация: 05.06.2014
Сообщений: 4,320
29.09.2015, 08:02  [ТС] #3
Цитата Сообщение от Ilot Посмотреть сообщение
Потому что назначение std::ios выполнять форматирование ввода/вывода, а std::streambuf читать/писать из/в устройства.
Но при этом эти два класса не являются самостоятельными сущностями. std::streambuf не используется нигде за пределами std::ios и его наследников, а std::ios в свою очередь не работает без std::streambuf. Я понимаю зачем разделять их на два класса, но на два объекта то какой смысл?
0
ShadowFirst
55 / 48 / 13
Регистрация: 31.10.2013
Сообщений: 164
29.09.2015, 08:44 #4
Есть такое понятие как наследование и компазиция. Компазиция это как раз то что там есть, то есть создается объект внутри класса, а не происходит наследование. В умных книжках как раз говориться что наследование нужно использовать в крайнем случае, когда используется полиморфизм например, а так лучше использовать компазицию.
0
Renji
2123 / 1482 / 452
Регистрация: 05.06.2014
Сообщений: 4,320
29.09.2015, 08:47  [ТС] #5
Цитата Сообщение от ShadowFirst Посмотреть сообщение
В умных книжках как раз говориться что наследование нужно использовать в крайнем случае, когда используется полиморфизм например, а так лучше использовать компазицию.
Дык в std::streambuf полиморфизм и используется. Он работает только через перегруженные потомком методы.
Цитата Сообщение от ShadowFirst Посмотреть сообщение
Компазиция это как раз то что там есть, то есть создается объект внутри класса, а не происходит наследование.
Не создается он. Объект std::streambuf (вернее, его потомок) должен создавать потомок, а потом передавать std::ios. И вот зачем такой изврат - я понять не могу.
0
hoggy
Заблокирован
29.09.2015, 09:05 #6
Цитата Сообщение от Renji Посмотреть сообщение
Но при этом эти два класса не являются самостоятельными сущностями.
на самом деле вполне себе самостоятельные.
к тому же решают различные задачи.

посмотрите внимательно на этот пример:
http://www.cplusplus.com/reference/ios/ios/rdbuf/

представьте себе, что std::ios - это магнитофон.
магнитофоны бывают разные.
они по разному воспроизводят получаемые данные.

а std::streambuf - устройство, которое непосредственно работает
с физическим источником данных:
кассеты, пластинки, копакт диски.
назовем его "стриммером".

любые stl-compatible магнитофоны умеют
с любыми stl-compatible стриммерами.
благодаря стандартизированному интерфейсу.

данная архитектура позволяет извлечь стриммер из одного магнитофона,
и вставить его в другой.

таким образом, получается, что std::streambuf определяет,
как прочитать байтики из источника.
а std::ios определяет, как эти байтики интерпритировать.

пример:
можно подсунуть std::streambuf в корпус zipstream, и поиметь зазипованный архив так же просто,
как и обычный текстовый/бинарный файл.

можно подсунуть какой нибудь замороченный custom::streambuf в обычный std::cout,
и вывести в консольку данные с како нибудь сильно замороченного носителя.
0
Ilot
Эксперт С++
1826 / 1184 / 342
Регистрация: 16.05.2013
Сообщений: 3,119
Записей в блоге: 5
Завершенные тесты: 1
29.09.2015, 09:08 #7
Цитата Сообщение от Renji Посмотреть сообщение
Но при этом эти два класса не являются самостоятельными сущностями. std::streambuf не используется нигде за пределами std::ios и его наследников, а std::ios в свою очередь не работает без std::streambuf. Я понимаю зачем разделять их на два класса, но на два объекта то какой смысл?
Пример паттерна "мост". Разделение интерфейса и реализации. Чтение/запись для разных устройств на разных платформах разный. Подобное разделение позволяет писать код вне зависимости от устройства/платформы.
Тем более, что и обязанности у них разные:
Цитата Сообщение от Ilot Посмотреть сообщение
Потому что назначение std::ios выполнять форматирование ввода/вывода, а std::streambuf читать/писать из/в устройства.
0
Renji
2123 / 1482 / 452
Регистрация: 05.06.2014
Сообщений: 4,320
29.09.2015, 09:59  [ТС] #8
Цитата Сообщение от hoggy Посмотреть сообщение
посмотрите внимательно на этот пример:
Посмотрел. Пример переопределяет поведение глобальной переменной cout. Нужно это только потому что программист не может поменять объявление этой глобальной переменной. И таких переменных в стандартной библиотеке целых три - cout, cin, cerr. Вся свистопляска ради трех переменных что ли?
Цитата Сообщение от hoggy Посмотреть сообщение
можно подсунуть какой нибудь замороченный custom::streambuf в обычный std::cout,
и вывести в консольку данные с како нибудь сильно замороченного носителя.
А можно тупо объявить глобальную переменную custom::iostream my_cout. Но понимаю, код прибит к cout гвоздями.
Цитата Сообщение от Ilot Посмотреть сообщение
Пример паттерна "мост". Разделение интерфейса и реализации. Чтение/запись для разных устройств на разных платформах разный. Подобное разделение позволяет писать код вне зависимости от устройства/платформы.
Кросс-платформенная функция пишет через std::ostream&stream (дальний потомок std::ios). Объясните тупому на пальцах какая функции разница, есть внутри std::ostream паттерн "мост" или нет (ссылка std::ostream& скушает любых потомков std::ostream, с любыми перегрузками методов).
0
Ilot
Эксперт С++
1826 / 1184 / 342
Регистрация: 16.05.2013
Сообщений: 3,119
Записей в блоге: 5
Завершенные тесты: 1
29.09.2015, 10:18 #9
Цитата Сообщение от Renji Посмотреть сообщение
Кросс-платформенная функция пишет через std::ostream&stream (дальний потомок std::ios).
Было же написанно и неоднократно std::ios не пишет/читает из устройства. Наследники этого класса управляют форматированием, а запись/чтение делегируют буферу. Можно прямо работать с буфером минуя потоки.
Цитата Сообщение от Renji Посмотреть сообщение
Объясните тупому на пальцах какая функции разница, есть внутри std::ostream паттерн "мост" или нет (ссылка std::ostream& скушает любых потомков std::ostream, с любыми перегрузками методов).
Все верно. Так и задумывалось. Т.е. создать интерфейс для однообразной работы с разными устройствами. Но так как потоки переехали из распространенной в то время библиотеки ввода/вывода то вопросы следует задавать ее разработчикам.
1
Renji
2123 / 1482 / 452
Регистрация: 05.06.2014
Сообщений: 4,320
29.09.2015, 10:19  [ТС] #10
Цитата Сообщение от Ilot Посмотреть сообщение
Но так как потоки переехали из распространенной в то время библиотеки ввода/вывода то вопросы следует задавать ее разработчикам.
А, то есть такая архитектура по наследству досталась. Это уже понятнее, спасибо.
0
hoggy
Заблокирован
29.09.2015, 13:51 #11
Цитата Сообщение от Renji Посмотреть сообщение
Вся свистопляска ради трех переменных что ли?
ради возможности цеплять к уже существующим механизмам любые источники данных,
и любые преобразователи этих данных.
0
Renji
2123 / 1482 / 452
Регистрация: 05.06.2014
Сообщений: 4,320
29.09.2015, 19:41  [ТС] #12
Цитата Сообщение от hoggy Посмотреть сообщение
ради возможности цеплять к уже существующим механизмам любые источники данных,
и любые преобразователи этих данных.
Эта возможность есть и при наследовании std::ios от streambuf.
C++
1
2
3
4
5
6
7
8
class my_stream:public std::istream,std::streambuf
{
public:
    //ну вот какая нафиг разница, написано здесь istream(this) или istream(new my_streambuf())?
    my_stream():istream((std::streambuf*)this){}
private:
    //реализация моего собственного std::streambuf
};
0
hoggy
Заблокирован
29.09.2015, 19:58 #13
Цитата Сообщение от Renji Посмотреть сообщение
Эта возможность есть и при наследовании std::ios от streambuf.
есть особое устройство, которое стандартный streambuf не поддерживает.

я хочу вывести данные в консоль.
(или на диск, или в зип, или в базу данных, это не принципиально).
из нового носителя данных.

зачем мне велосипедить стандартный стрим,
если достаточно завелосипедить только наследника std::streambuf,
а весь остальной код останется без изменений?
зачем велосипедить, если можно по максимуму использовать stl ?

так реализуется идеома "закрыт для изменений, открыт для расширений".
весь уже написанный и протестированный код остается без изменений.
функционал наращивается, но старый не изменяется.

конечно, в суровой реальности все не так безоблачно прекрасно.
но в целом эта идея работает.
0
Renji
2123 / 1482 / 452
Регистрация: 05.06.2014
Сообщений: 4,320
29.09.2015, 20:13  [ТС] #14
Цитата Сообщение от hoggy Посмотреть сообщение
зачем мне велосипедить стандартный стрим,
если достаточно завелосипедить только наследника std::streambuf,
а весь остальной код останется без изменений?
Ткните пальцем, где в моем примере с наследованием, меняется код не относящийся к streambuf.
C++
1
2
3
4
5
6
7
8
9
10
11
12
class bicycle_stream:std::ostream,std::streambuf
{
public:
    bicycle_stream():ostream(this){}
private:
    //реализация интерфейса streambuf
    streamsize xsputn (const char* s, streamsize n){
        for(;n;--n)
            cout<<*s++;
    }
    //реализация своего интерфейса ostream. Ровно ноль строк
};
0
hoggy
Заблокирован
29.09.2015, 20:19 #15
Цитата Сообщение от Renji Посмотреть сообщение
Ткните пальцем, где в моем примере с наследованием, меняется код не относящийся к streambuf.
выше я приводил вам пример подмены стриммера.

приведите мне аналогичный пример.

с использованием вашего подхода.

требуются преобразования:

zipstream <---> ostream, fstream.

наследник streambuf читает видеопоток,
и распознает особые маркеры среди потока байтиков,


то есть не обязательно писать код алгоритмов.
интересует архитектурное решение.

ваш bicycle_stream сейчас нарушают идеому
"закрыт для изменений, открыт для расширений".

нужно знать про какой то bicycle_stream,
что бы записать данные на диск?
0
Renji
2123 / 1482 / 452
Регистрация: 05.06.2014
Сообщений: 4,320
29.09.2015, 20:26  [ТС] #16
Цитата Сообщение от hoggy Посмотреть сообщение
приведите мне аналогичный пример.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
void any_stream_print(std::ostream&stream,const char*str)
{
    stream<<"Мы принимаем любых потомков ostream! Вы хотели напечатать: "<<str;
}
int main()
{
    zipstream zstream;
    bicycle_stream bstream;
    any_stream_print(cout,"Это cout");
    any_stream_print(zstream,"Это zstream");
    any_stream_print(bstream,"Это велосипед");
    return 0;
}
0
hoggy
Заблокирован
29.09.2015, 20:29 #17
Цитата Сообщение от Renji Посмотреть сообщение
stream<<"Мы принимаем любых потомков ostream! Вы хотели напечатать: "<<str;
у меня в исходном коде фигурирует:

C++
1
os << data; // os - ostream
мне теперь код переписывать придется?
0
Renji
2123 / 1482 / 452
Регистрация: 05.06.2014
Сообщений: 4,320
29.09.2015, 21:21  [ТС] #18
Цитата Сообщение от hoggy Посмотреть сообщение
у меня в исходном коде фигурирует:
А у меня фигурирует:
C++
1
2
3
is.seekg(save_pos);
getline(is,line);
throw std::runtime_error("Can't parse \""+line+"\"");
Теперь дописываем к этому делу is.rdbuf(cin.rdbuf()) и программа падает. Потому как cin никаких seekg скорее всего не поддерживает.
Цитата Сообщение от hoggy Посмотреть сообщение
мне теперь код переписывать придется?
Конечно. Программа должна быть изначально рассчитана на работу с произвольным потоком. В документации должно быть изначально подписано что этот поток должен поддерживать. Иначе попытки заменить один поток другим будут иметь непредсказуемые последствия. Если же программа уже рассчитана на поддержку произвольных потоков, то и rdbuf костыль ей без надобности.
0
29.09.2015, 21:21
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.09.2015, 21:21
Привет! Вот еще темы с решениями:

Перевод десятичного числа во внутреннее представление
Всем привет. Сделал программу перевода десятичного числа во внутреннее...

Неправильно отображает внутреннее представление типа double
Тип int отображается верно, а вот при double ошибка Для числа 5: int :...

Внутреннее (машинное) представление данных двух типов
Разработать программу, которая выводит на экран внутреннее (машинное)...

Внутреннее представление типа Double через Long
Привет. Для оптимизации работы одного вычислительного алгоритма потребовалось...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru