This is how I usually read files with std::ifstream:
while (InFile.peek() != EOF)
{
char Character = InFile.get();
// Do stuff with Character...
}
This avoids the need of an if statement inside the loop. However, it seems that even peek() causes eofbit to be set, which makes calling clear() necessary if I plan on using that same stream later.
Is there a cleaner way to do this?
asked Apr 7, 2011 at 14:41
4
Typically, you would just use
char x;
while(file >> x) {
// do something with x
}
// now clear file if you want
If you forget to clear(), then use an RAII scope-based class.
Edit: Given a little more information, I’d just say
class FileReader {
std::stringstream str;
public:
FileReader(std::string filename) {
std::ifstream file(filename);
file >> str.rdbuf();
}
std::stringstream Contents() {
return str;
}
};
Now you can just get a copy and not have to clear() the stream every time. Or you could have a self-clearing reference.
template<typename T> class SelfClearingReference {
T* t;
public:
SelfClearingReference(T& tref)
: t(&tref) {}
~SelfClearingReference() {
tref->clear();
}
template<typename Operand> T& operator>>(Operand& op) {
return *t >> op;
}
};
answered Apr 7, 2011 at 14:54
PuppyPuppy
144k37 gold badges255 silver badges462 bronze badges
0
I’m not sure I understand. Infile.peek() only sets eofbit
when it returns EOF. And if it returns EOF, and later read
is bound to fail; the fact that it sets eofbit is an
optimization, more than anything else.
answered Apr 7, 2011 at 17:26
James KanzeJames Kanze
150k18 gold badges184 silver badges329 bronze badges
1
Что за ошибки? На 25 строке «‘StringReader’ не содержит конструктор, который принимает аргументы 2». и на 26 «Не удается преобразовать группу методов «ReadToEnd» в тип, не являющийся делегатом «string». Предполагалось вызывать этот метод?». Можете поподробнее рассказать о появление этих ошибок и как их избежать?
задан 31 окт 2017 в 17:09
4
Как видно тут конструктор StringReader принимает только 1 аргумент String, так что Encoding.Unicode нужно убрать. А в 26 строчке надо написать string content_f = reader_f.ReadToEnd().
ответ дан 31 окт 2017 в 17:20
pinguinpinguin
1,8332 золотых знака10 серебряных знаков22 бронзовых знака
5
sArray в C++ — это контейнер, который хранит элементы в динамическом массиве. Он очень похож на стандартный массив в C++, но имеет дополнительные функции для работы с данными. Читать данные из sArray может быть проблематично, если не знать особенностей его использования. Этот материал расскажет, как избежать ошибок при чтении данных из sArray в C++.
Использование оператора []
Один из самых простых способов получения элементов из sArray — использование оператора []. Этот оператор возвращает элемент по его индексу. Например:
sArray<int> arr {1, 2, 3};
int element = arr[0]; // Получаем первый элемент
Но использование оператора [] не всегда безопасно. Если мы выходим за пределы массива, программа может выйти из строя или получить неожиданные результаты. Чтобы избежать этой ошибки, всегда проверяйте границы массива перед использованием оператора []. Например:
sArray<int> arr {1, 2, 3};
if (index >= 0 && index < arr.size()) {
int element = arr[index]; // Получаем элемент по индексу
} else {
// Обработка ошибки
}
Использование метода at()
Метод at() похож на оператор [], но он более безопасен. Он возвращает элемент по индексу и проверяет границы массива. Если мы пытаемся получить элемент за пределами массива, этот метод выбрасывает исключение std::out_of_range. Например:
sArray<int> arr {1, 2, 3};
try {
int element = arr.at(index); // Получаем элемент по индексу
} catch (std::out_of_range& e) {
// Обработка ошибки
}
Использование итераторов
Итераторы — это объекты, которые позволяют нам обходить элементы sArray. Существует несколько типов итераторов, но в этом материале мы будем использовать обычный итератор. Мы можем получить итератор с помощью метода begin() и end(). Метод begin() возвращает итератор на первый элемент, а метод end() — на элемент, следующий за последним. Например:
sArray<int> arr {1, 2, 3};
for (sArray<int>::iterator it = arr.begin(); it != arr.end(); ++it) {
int element = *it; // Получаем элемент по итератору
}
Заключение
Чтение данных из sArray может быть опасно, если мы не знаем, как избежать ошибок. Когда мы читаем данные из sArray, мы должны всегда проверять границы массива перед использованием оператора [], использовать метод at(), который выбрасывает исключение при выходе за пределы массива, и использовать итераторы для обхода элементов. Надеюсь, этот материал помог вам избежать ошибок при работе с sArray в C++.
Как я могу избежать ошибок при передаче параметров одного типа в функцию?
Давайте рассмотрим функцию чтения некоторых двоичных данных:
std::vector<uint8_t> read(size_t offset, size_t amount);
Это так легко перепутать с количеством (я делал это много раз).
Я вижу решение этого:
struct Offset
{
explicit Offset(size_t value) : value{value}{}
size_t value;
};
struct Amount
{
explicit Amount(size_t value) : value{value}{}
size_t value;
};
std::vector<uint8_t> read(Offset offset, Amount amount);
Есть ли лучшее решение, чтобы избежать подобных ошибок?
0
Решение
Еще одна вещь, которую вы можете сделать, это передать параметры в структуре. Это также позволяет вам установить разумные значения по умолчанию для значений. Это особенно полезно, когда конструктор принимает большое количество аргументов. Например:
class FooService
{
public:
// parameters struct.
struct Options
{
ip::address listen_address = ip::address::any();
uint16_t port = 1337;
bool allow_insecure_requests = false;
std::string base_directory = "/var/foo/"};
//constructor takes the options struct to pass values.
explicit FooService(FooServiceOptions options);
// ...
};
Который затем используется как:
FooService::Options o;
o.port = 1338;
//all other values keep their defaults.
auto service = make_unique<FooService>(o);
0
Другие решения
Есть два подхода, которые я могу придумать.
Помеченные типы
По сути, это то, что вы предлагаете в своем вопросе, но я бы реализовал это в общих чертах.
template <typename Tag, typename T>
struct Tagged
{
explicit Tagged(const T& value) : value{value} { }
T value;
};
template <typename Tag, typename T>
Tagged<Tag, T> tag(const T& value)
{
return Tagged<Tag, T>{value};
}
struct OffsetTag
{ };
struct AmountTag
{ };
using Offset = Tagged<OffsetTag, std::size_t>;
using Amount = Tagged<AmountTag, std::size_t>;
std::vector<uint8_t> read(Offset offset, Amount amount);
Это позволяет расширить ту же концепцию на другие базовые типы данных.
Идиома Именованного Параметра
Идиома Именованного Параметра чем-то похож на Options подход в ответе @ PaulBelanger, но он может быть использован на месте и не позволяет пользователю использовать ярлык с фигурными скобками, который возвращает вас к той же проблеме, что и раньше. Тем не менее, он по умолчанию инициализирует все ваши параметры, поэтому, хотя вы защищены от смешения параметров, он не может заставить вас предоставить явные значения для всех них. Для вашего примера:
class ReadParams
{
public:
ReadParams() : m_offset{0}, m_amount{128}
{ }
ReadParams& offset(std::size_t offset)
{
m_offset = offset;
return *this;
}
// Could get rid of this getter if you can make the users
// of this class friends.
std::size_t offset() const { return m_offset; }
ReadParams& amount(std::size_t amount)
{
m_amount = amount;
return *this;
}
// Could get rid of this getter if you can make the users
// of this class friends.
std::size_t amount() const { return m_amount; }
private:
std::size_t m_offset;
std::size_t m_amount;
};
std::vector<uint8_t> read(const ReadParams& params);
int main()
{
read(ReadParams{}.offset(42).amount(2048)); // clear parameter names
// read(ReadParams{42, 2048}); // won't compile
read(ReadParams{}.offset(42)); // also possible, amount uses default value
}
Вы могли бы реализовать членов ReadParams как std::optionals и выдает ошибку времени выполнения, если неинициализированный член имеет доступ; но вы больше не можете применять во время компиляции что пользователь фактически предоставляет все параметры.
0
0 / 0 / 0
Регистрация: 24.12.2019
Сообщений: 3
1
24.12.2019, 01:02. Показов 2675. Ответов 5

Здравствуйте! Заранее прошу прощения что прикрепляю весь код, боюсь упустить важное.
Я в виде практики пытаюсь написать клон Space Invaders. И все вроде бы понятно, но программа крашится. Компиляция проходит успешно, но логической ошибки избежать не могу.
Признаюсь, я не очень хорош в указателях, поэтому, думаю, что проблема кроется в них.
В попытках решить проблему, я избавился от
в пользу
, добавил несколько virtual destructors, попытался больше использовать
— ничего не помогает.
Мне кажется, что объект приходит пустым, но я не могу отследить где именно и почему он стерается.
| C++ | ||
|
Так же, VS выдает следующую инфу (скрин прикреплен).
Еще раз прошу прощения за выкладывание всего кода.
Заранее спасибо за любую помощь.
Миниатюры
0

