Я разрабатываю небольшую библиотеку для использования с приложениями командной строки. Одной из особенностей этой библиотеки является то, что он является основным классом может производить текст в Ostream, как таковой:

#include <iostream>    

class MyClass {
    std::string a;
    std::string b;

    void printToStream(std::ostream& stream = std::cout)
    {
        stream << "a: " << a << " | b: " << b << std::endl;
    }
}

Мой вопрос касается использования std :: cout в качестве аргумента по умолчанию. Это просто для того, чтобы упростить использование библиотеки, поскольку она ориентирована на приложения командной строки, как я уже говорил ранее, поэтому в большинстве случаев желаемый вывод должен быть стандартным выводом, но в случае, если пользователю нужен другой поток вывода они могут предоставить его сами.

Это единственная точка в моей библиотеке, где используется что-либо из iostream, поэтому мне интересно, вызывает ли такой аргумент по умолчанию, вызывает любую потерю эффективности. Из того, что я понимаю, iostream - бегемот, тактовой в более чем 25 000 строк кода, и он включен довольно безвозмездно, должен ли пользователь предоставить свой собственный выходной поток.

Кроме того, я понимаю, что компилятор, вероятно, достаточно умен, чтобы не включать что-либо из iostream в окончательный исполняемый файл, если cout здесь не используется, но я хотел бы знать полное влияние этого включения в моей библиотеке - и есть ли лучший способ реализовать cout в качестве аргумента по умолчанию, не заставляя пользователя строить против iostream, когда в этом нет необходимости.

1
RenanB 8 Мар 2018 в 07:17

1 ответ

Лучший ответ

Очень короткий ответ: вероятно, не ваше самое важное решение, когда речь идет о ваших программированных усилиях.

Гораздо более длинный ответ, который на самом деле не говорит вам намного больше, чем указано выше, но вы все равно можете найти его интересным, если вы к этому склонны.

Это один из тех вопросов, которые сильно зависят от того, насколько чувствительна ваша среда. Если вы строите систему с 256 КБ ОЗУ, и вам приходится соответствовать нескольким приложениям, операционной системе и двигателю базы данных во все это, очевидно, когда-либо, когда-либо килобайт прикладного пространства является драгоценным. С другой стороны, на моем ноутбуке или настольном компьютере, где память рассчитывается в более мегабайтах, чем пальцами, наверное, вообще ничего не беспокоиться. В середине системы диапазона с несколькими мегабайтами оперативной памяти не является вашим первым приоритетом для поддержания размера кода.

Я быстро написал два простых приложения, используя один файл заголовка:

< Сильный > myclass.h :

#include <iostream>    

class MyClass {
public:
    std::string a;
    std::string b;

    void printToStream(std::ostream& stream = std::cout)
    {
        stream << "a: " << a << " | b: " << b << std::endl;
    }
};

Тогда то, что «использует» printToStream:

uses.cpp:

#include "myclass.h"

int main()
{
    MyClass m;
    m.a = "Hello";
    m.b = "World";
    m.printToStream();
}

Размер в G ++ -O1: 3502 байты, Clang ++ -O1: 4409

И тот, который не использует printToStream:

nouse.cpp:

#include "myclass.h"

int main()
{
    MyClass m;
    m.a = "Hello";
    m.b = "World";
}

Размер в g ++ -O1: 2349 байт, clang ++ -O1: 2923

Разница размеров составляет около 1500 байтов с Clang ++ -O1 и 1200 байтами с G ++ -O1. Общий размер кода составляет около 2,5-4КБ, поэтому его около 30% от общего размера в этом крошечном примере. Очевидно, что это далеко от линейного - как только вы используете std::cout, инициализация там для всех используемых использований.

Если я изменю файл myclass.h на #include <string> и полностью удалю ссылки на поток, он дополнительно удалит около 300 байтов кода из сгенерированного двоичного файла nouse.cpp. Это показывает, что ТОЛЬКО включение <iostream> добавит некоторый код в ваш двоичный файл. Однако использование <ostream> вместо <iostream> не влияет на созданный двоичный файл.

Я также попробовал удалить аргумент std::cout по умолчанию. Это не имело никакой разницы (за исключением изменений кода, чтобы иметь дополнительный аргумент в uses.cpp), поэтому размер идентичен. Он также не влияет на nouse.cpp - дополнительный код все еще там инициализации cout.

Точно так же включение <ostream>, а затем включение <iostream> в основной файл не влияет на размер uses.cpp (без использования аргумента по умолчанию).

Я тоже попробовал -O2, и он делает размер изменения кода (больше в G ++, меньший для Clang ++), но относительная разница не очень большая.

Очевидно, это для двух экземпляров двух самых популярных компиляторов C ++ с открытым исходным кодом. Другие компиляторы, вероятно, дадут несколько другие результаты. Если это очень важно, проверьте свой компилятор.

Версия G ++: 7.2.0, поставляемая с UBUTT, CLANG ++: 7.0.0 (построена из источников с Git Versions Clang 16003BCDB4287AAB3B87300D9E95F9B49CE52C1C, LLVM 45EBD75CC103838DA0B3938AC5D044EC8A7FF17B)

1
Mats Petersson 8 Мар 2018 в 11:53