Действительно ли это стоит вперед объявляющих классов библиотеки?

Ваша программа делает то, что вы кодировали (если вы исправили ошибку IndentationError, скопированную в SO) - первое значение никогда не записывается в файл:

outfile = open("userInput.txt","w")
userInput = int(input("Enter a number to the text file: "))     # THIS is the first input
count = 0
while int(userInput) != -1:
   userInput = int(input("Enter a number to the text file: "))  # second to last input
   outfile.write(str(userInput) + "\n")                         # here you write it
   count +=1
if(count) == 0:
   print("There is no numbers in the text file")
   outfile.write("There is no numbers in the text file")
outfile.close()
blockquote>

Измените его на:

count = 0
userInput = 99  # different from -1
with open ("userInput.txt","w") as outfile:
    while userInput != -1:
        userInput = int(input("Enter a number to the text file: "))
        if userInput != -1:
            outfile.write(str(userInput) + "\n") 
        else:
            outfile.write("There is no numbers in the text file\n") 

        count +=1

print("Done")

Запишет хотя бы 1 цифру или текст в ваш файл.


Возможно, вы захотите прочитать Запрашивать у пользователя вводные данные, пока они не дадут действительный ответ , чтобы получить вдохновение, как избежать ValueErrors из int("some not numer").

Это Как отлаживать небольшие программы может помочь отладить ваши программы в будущем.

8
задан Skilldrick 26 April 2009 в 16:15
поделиться

8 ответов

Абсолютно. Модель сборки C / C ++ - это ... хм ... анахронизм (если говорить лучше). Для крупных проектов это становится серьезным PITA.

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

Breaking Circular включают ссылки это единственная причина, по которой вам нужно использовать предварительные объявления.

// a.h
#include "b.h"
struct A { B * a;  }

// b.h
#include "a.h"  // circlular include reference 
struct B { A * a;  }

// Solution: break circular reference by forward delcaration of B or A

Сокращение времени перестроения . Представьте себе следующий код

// foo.h
#include <qslider>
class Foo
{
   QSlider * someSlider;
}

, теперь каждый файл .cpp, который прямо или косвенно извлекает файл Foo.h, также извлекает файл QSlider.h и все его зависимости. Это могут быть сотни .cpp файлов! (Предварительно скомпилированные заголовки помогают немного - а иногда и много - но они превращают давление диска / процессора в память / давление диска и, таким образом, вскоре достигают «следующего» limit)

Если заголовок требует только ссылочного объявления, эта зависимость часто может быть ограничена несколькими файлами, например, foo.cpp.

Сокращение времени инкрементной сборки - Эффект еще более выражен при работе с собственными (а не стабильными библиотеками) заголовками. Представьте, что у вас есть

// bar.h
#include "foo.h"
class Bar 
{
   Foo * kungFoo;
   // ...
}

Теперь, если большинству ваших .cpp нужно добавить bar.h, они также косвенно добавят foo.h. Таким образом, каждое изменение foo.h запускает сборку всех этих файлов .cpp (которые могут даже не знать Foo!). Если вместо этого bar.h использует прямое объявление для Foo, зависимость от foo.h ограничивается bar.cpp:

// bar.h
class Foo;
class Bar 
{
   Foo * kungFoo;
   // ...
}

// bar.cpp
#include "bar.h"
#include "foo.h"
// ...

Это настолько распространено, что это шаблон - шаблон PIMPL , Его использование имеет два аспекта: во-первых, он обеспечивает истинную изоляцию интерфейса / реализации, а другой уменьшает зависимости при сборке. На практике я d оцените их полезность 50:50.

Вам нужна ссылка в заголовке, вы не можете иметь прямую реализацию зависимого типа. Это ограничивает случаи, когда могут применяться предварительные декларации. Если вы делаете это явно, для этого обычно используется служебный класс (такой как boost :: scoped_ptr ).

Стоит ли время сборки? Определенно , я ' скажу В худшем случае время сборки растет полиномом с количеством файлов в проекте. другие методы - например, более быстрые машины и параллельные сборки - могут обеспечить только процентное увеличение.

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

На практике, управляя временем сборки, Несмотря на то, что это важно для большого проекта (скажем, для сотен исходных файлов), оно все же создает «разницу в комфорте» для небольших проектов. Кроме того, добавление улучшений после факта часто является упражнением в терпении, так как одно исправление может сбрить только секунды (или меньше) 40-минутной сборки.

17
ответ дан 5 December 2019 в 05:34
поделиться

Я использую его все время. Мое правило: если заголовок не нужен, я помещаю предварительное объявление ( «используйте заголовки, если нужно, используйте предварительные объявления, если можете» ). Единственное, что отстой, - это то, что мне нужно знать, как был объявлен класс (struct / class, возможно, если это шаблон, мне нужны его параметры, ...). Но в подавляющем большинстве случаев это просто сводится к «классу Slider» или к чему-то подобному. Если что-то требует, чтобы было объявлено еще больше хлопот, всегда можно объявить специальный заголовок предварительного объявления, как это делает Стандарт с iosfwd .

Отсутствие заголовочного файла не только сократит время компиляции, но и позволит избежать загрязнения пространства имен. Файлы с заголовком будут благодарны вам за то, что вы включили как можно меньше, чтобы они могли использовать чистую среду.

Это приблизительный план:

/* --- --- --- Y.hpp */
class X;
class Y {
    X *x;
};

/* --- --- --- Y.cpp */
#include <x.hpp>
#include <y.hpp>

...

Существуют умные указатели, специально предназначенные для работы с указателями на неполные типы. Один очень хорошо известный - boost :: shared_ptr .

8
ответ дан 5 December 2019 в 05:34
поделиться

Да, это действительно помогает. Еще одна вещь, которую нужно добавить в свой репертуар - это предварительно скомпилированные заголовки, если вас беспокоит время компиляции.

Посмотрите FAQ 39.12 и 39.13

3
ответ дан 5 December 2019 в 05:34
поделиться

Стандартная библиотека делает это для некоторых классов iostream в стандартном заголовке . Тем не менее, это не общеприменимый метод - обратите внимание, что для других типов стандартных библиотек таких заголовков нет, и он не должен (IMHO) быть вашим подходом по умолчанию для разработки классов-иерархий.

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

2
ответ дан 5 December 2019 в 05:34
поделиться

Существует огромная разница во времени компиляции для более крупных проектов, даже с тщательно управляемыми зависимостями. Вам лучше привыкнуть объявлять вперед и хранить как можно больше вне заголовочных файлов, потому что во многих магазинах программного обеспечения, использующих C ++, это требуется. Причина, по которой вы не видите этого в стандартных заголовочных файлах, заключается в том, что они интенсивно используют шаблоны, и в этот момент объявление становится сложным. Для MSVC вы можете использовать / P, чтобы посмотреть, как выглядит предварительно обработанный файл перед фактической компиляцией. Если вы не сделали каких-либо предварительных деклараций в своем проекте, вероятно, было бы интересно узнать, сколько дополнительной обработки необходимо выполнить.

1
ответ дан 5 December 2019 в 05:34
поделиться

В общем, нет.

Я использовал для пересылки объявлений столько, сколько мог, но не больше.

Что касается Qt, вы можете заметить, что существует включает файл, который включает все виджеты GUI. Также есть , , и т. Д. Для каждого модуля есть файл заголовка. Похоже, что команда Qt также считает этот метод предпочтительным. Они так говорят в документации к своим модулям.

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

0
ответ дан 5 December 2019 в 05:34
поделиться

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

-1
ответ дан 5 December 2019 в 05:34
поделиться

Когда вы пишете ...

включаете "foo.h"

... тем самым вы инструктируете обычный build system "В любое время, когда в библиотечном файле foo.h есть какие-либо изменения, откажитесь от этого модуля компиляции и пересоберите его, даже если все, что случилось с foo.h, это добавление комментария или добавление комментария к некоторому файл, который включает в себя foo.h; даже если все, что произошло, было каким-то неаккуратным коллегой, перебалансировало фигурные скобки; даже если ничего не произошло, за исключением того, что находящийся под давлением коллега зарегистрировал foo.h без изменений и случайно изменил его временную метку. "

Почему вы хотите дать такую ​​команду? Заголовки библиотек, поскольку в целом они имеют больше читателей-людей, чем заголовков приложений, имеют особую уязвимость к изменениям, которые не влияют на двоичный файл, таким как улучшенное документирование функций и аргументов или изменение номера версии или даты авторского права.

Правила C ++ позволяют повторно открывать пространство имен в любой точке модуля компиляции (в отличие от struct или класса ) для поддержки прямого объявления.

Правила C ++ позволяют повторно открывать пространство имен в любой точке модуля компиляции (в отличие от struct или класса ) для поддержки forward. декларация.

Правила C ++ позволяют повторно открывать пространство имен в любой точке модуля компиляции (в отличие от struct или класса ) для поддержки forward. декларация.

0
ответ дан 5 December 2019 в 05:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: