С как избежать ошибки read

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

Maxpm's user avatar

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

Puppy's user avatar

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 Kanze's user avatar

James KanzeJames Kanze

150k18 gold badges184 silver badges329 bronze badges

1

А вот участок кода где есть 2 ошибки.

Что за ошибки? На 25 строке «‘StringReader’ не содержит конструктор, который принимает аргументы 2». и на 26 «Не удается преобразовать группу методов «ReadToEnd» в тип, не являющийся делегатом «string». Предполагалось вызывать этот метод?». Можете поподробнее рассказать о появление этих ошибок и как их избежать?

задан 31 окт 2017 в 17:09

GeVa Main's user avatar

4

Как видно тут конструктор StringReader принимает только 1 аргумент String, так что Encoding.Unicode нужно убрать. А в 26 строчке надо написать string content_f = reader_f.ReadToEnd().

ответ дан 31 окт 2017 в 17:20

pinguin's user avatar

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++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
#include "stdafx.h"
#include <vector>
#include <random>
#include <chrono>
#include <thread>
#include <memory>
#include <SDKDDKVer.h>
#include "Vector2D.h"
#include "Renderer.h"
 
std::default_random_engine rGen;
typedef std::uniform_int_distribution<int> intRand;
typedef std::uniform_real_distribution<float> floatRand;
 
char ObjectType[][64] =
{
    "ot_AlienShip",
    "ot_PlayerShip",
    "ot_AlienLaser",
    "ot_PlayerLaser",
    "ot_Explosion"
};
 
class PlayField;
class GameObject
{
public:
    //char* m_objType;
    std::string m_objType;
    GameObject* newObj = nullptr;
    Vector2D pos;
    unsigned char sprite = NULL;
 
    virtual void Update(PlayField& world) {};
    virtual bool DecreaseHealth() { return true; };
    virtual ~GameObject() {};
};
 
class Input
{
public:
    virtual bool Left() = 0;
    virtual bool Right() = 0;
    virtual bool Fire() = 0;
    virtual ~Input() {};
};
 
class RndInput : public Input
{
public: 
    virtual bool Left() override { floatRand keyRate(0, 1); return (keyRate(rGen) < 0.3f); }
    virtual bool Right() override { floatRand keyRate(0, 1); return (keyRate(rGen) < 0.4f); };
    virtual bool Fire() override { floatRand keyRate(0, 1); return (keyRate(rGen) < 0.5f); };
};
 
class PlayField
{
private:
    typedef GameObject* GameObjPtr;
    std::vector<GameObjPtr> gameObjects{};
 
 
public:
    Input* cotrollerInput = nullptr;
    Vector2D bounds;
    // Number of available active laser slots for aliens and player
    int AlienLasers = 10;
    int PlayerLasers = 4;
 
    explicit PlayField(Vector2D iBounds) : bounds(iBounds) {};
    const std::vector<GameObjPtr>& GameObjects() { return gameObjects; }
 
    void Update()
    {
        // update list of active objects in the world
        for (auto it : gameObjects)
        {
            it->Update(*this);  //На этой строчке краш! "Unhandled exception thrown: read access violation. it was 0xFFFFFFFFFFFFFFFF."
        }
    }
 
    GameObject* GetPlayerObject()
    {
        auto it = std::find_if(gameObjects.begin(), gameObjects.end(), [](GameObjPtr in) { return ((in->m_objType)=="ot_PlayerShip"); });
        if (it != gameObjects.end())
            return (*it);
        else
            return nullptr;
    }
 
    void SpawnLaser(GameObject* newObj)
    {
        if ((newObj->m_objType) == "ot_AlienLaser")
            AlienLasers--;
        else if ((newObj->m_objType) == "ot_PlayerLaser")
            PlayerLasers--;
        AddObject(newObj);
    }
    void DespawnLaser(GameObject* newObj)
    {
        if ((newObj->m_objType) == "ot_AlienLaser")
            AlienLasers++;
        else if ((newObj->m_objType) == "ot_PlayerLaser")
            PlayerLasers++;
        RemoveObject(newObj);
    }
 
    void AddObject(GameObject* newObj)
    {
        //gameObjectsToAdd.push_back(GameObjPtr(newObj));
        gameObjects.push_back(newObj);
    }
    void RemoveObject(GameObject* newObj)
    {
        //gameObjectsToRemove.push_back(newObj);
        auto it = std::find_if(gameObjects.begin(), gameObjects.end(), [&](GameObjPtr in) { return (in==newObj); });
        gameObjects.erase(it);
    }
};
 
class Explosion : public GameObject
{
public:
    // Explosion lasts 5 ticks before it dissappears
    int timer = 5;
    Explosion() { m_objType = new char[64];  (m_objType == "ot_Explosion"); sprite = RS_Explosion; }
    //~Explosion() { delete[] m_objType; }
    void Update(PlayField& world) override
    {
        timer--;
        if (!timer)
        {
            world.RemoveObject(this);
            delete this;
        }
    }
};
 
class AlienLaser : public GameObject
{
public:
    AlienLaser() { m_objType = new char[64]; (m_objType == "ot_AlienLaser"); sprite = RS_AlienLaser; }
    //~AlienLaser() {   delete[] m_objType; }
 
    void Update(PlayField& world) override
    {
        bool deleted = false;
        pos.y += 1.f;
        if (pos.y > world.bounds.y)
        {
            deleted = true;
        }
        GameObject* player = world.GetPlayerObject();
        if (player && pos.IntCmp(player->pos))
        {
            deleted = true;
            //Spawn explosion, kill player
            GameObject Explosion{};
            //GameObject& no = *(new Explosion);
            Explosion.pos = pos;
            world.AddObject(&Explosion);
            world.RemoveObject(player);
        }
 
        if (deleted)
        {
            world.DespawnLaser((GameObject*)this);
            delete this;
        }
    }
};
 
class PlayerLaser : public GameObject
{
public:
    PlayerLaser() { m_objType = new char[64]; (m_objType == "ot_PlayerLaser"); sprite = RS_PlayerLaser; }
    //~PlayerLaser() { delete[] m_objType; }
 
    void Update(PlayField& world) override
    {
        bool deleted = false;
        pos.y -= 1.f;
        if (pos.y < 0)
        {
            deleted = true;
        }
 
        for (auto it : world.GameObjects())
        {
            if ((it->m_objType) == "ot_AlienShip" && it->pos.IntCmp(pos))
            {
                deleted = true;
                //Spawn explosion, kill the alien that we hit
                //ToDo - add scoring
                GameObject Explosion{};
                //GameObject& no = *(new Explosion);
                Explosion.pos = pos;
                world.AddObject(&Explosion);
                if (it->DecreaseHealth())
                    world.RemoveObject(it);
            }
        }
 
        if (deleted)
        {
            world.DespawnLaser(this);
            delete this;
        }
    }
};
 
class Alien : public GameObject
{
public:
    Alien() { m_objType = new char[64]; (m_objType == "ot_AlienShip"); sprite = RS_Alien; }
    //~Alien() { delete m_objType; }
 
private:
    // Alien constants - these could move out into PlayField as configurable variables
    const float maxUpdateRate = 0.01f;
    const float transformEnergy = 1.f;
    enum AlienState
    {
        as_Normal,
        as_Better
    };
    // Variables dictating energy level for upgrade, direction of movement, and current speed
    float health = 1.f;
    float energy = 0.f;
    float direction = 1.f;
    float velocity = 0.5f;
    AlienState state{};
 
    void Transform()
    {
        state = as_Better;
        sprite = RS_BetterAlien;
        velocity *= 2.f;
    }
    bool DecreaseHealth() override { health -= 1.f; return health <= 0;  }
 
    void Update(PlayField& world) override
    {
        pos.x += direction * velocity;
        // Border check
        if (pos.x < 0 || pos.x >= world.bounds.x - 1)
        {
            direction = -direction;
            pos.y += 1;
        }
 
        // Border check vertical:
        if (pos.y >= world.bounds.y - 1)
        {
            // kill player
            GameObject* player = world.GetPlayerObject();
            if (player && pos.IntCmp(player->pos))
            {
                //Spawn explosion
                GameObject Explosion{};
                //GameObject& no = *(new Explosion);
                Explosion.pos = pos;
                world.AddObject(&Explosion);
                world.RemoveObject(player);
            }
        }
 
        // Transform into better Alien
        if (state!=as_Better)
        {
            floatRand updateRate(-maxUpdateRate, 2*maxUpdateRate);
            energy += updateRate(rGen);
            if (energy >= transformEnergy)
                Transform();
        }
 
        floatRand fireRate(0, 1);
        if (fireRate(rGen) < 0.5 && world.AlienLasers>0)
        {
            //Spawn laser
            GameObject AlienLaser{};
            //GameObject& newLaser = *(new AlienLaser);
            AlienLaser.pos = pos;
            world.SpawnLaser(&AlienLaser);
        }
    }
};
 
class PlayerShip : public GameObject
{
public:
    PlayerShip() { m_objType = new char[64]; (m_objType == "ot_PlayerShip"); sprite = RS_Player; }
    //~PlayerShip() { delete m_objType; }
 
    void Update(PlayField& world) override
    {
        if (world.cotrollerInput->Left())
            pos.x -= 1;
        else if (world.cotrollerInput->Right())
            pos.x += 1;
 
        if (world.cotrollerInput->Fire() && world.PlayerLasers>0)
        {
            //Spawn laser
            GameObject PlayerLaser{};
            //GameObject& newLaser = *(new PlayerLaser);
            PlayerLaser.pos = pos;
            world.SpawnLaser(&PlayerLaser);
        }
    }
};
 
int main()
{
    rGen.seed(1);
    Vector2D size(80, 28);
    Renderer mainRenderer(size);
    PlayField world(size);
 
    intRand xCoord(0, (int)size.x-1);
    intRand yCoord(0, 10);
 
    // Populate aliens
    for (int k = 0; k < 20; k++)
    {
        Alien a{};
        a.pos.x = (float)xCoord(rGen);
        a.pos.y = (float)yCoord(rGen);
        world.AddObject(&a);
    }
    // Add player
    PlayerShip p{};
    p.pos = Vector2D(40, 27);
    world.AddObject(&p);
 
#define TEST_RUN
#ifdef TEST_RUN
    // Test run with random input
 
    world.cotrollerInput = new RndInput;
    for (int i = 0; i < 100; i++)
#else
    // ToDo - implement keyboard (or other device input)
    //world.cotrollerInput = new KeyboardInput;
    while (;;) // break when game-over
#endif
 
        world.Update();
        {
            RenderItemList rl;
            for (auto it : world.GameObjects())
            {
                RenderItem a = RenderItem(Vector2D(it->pos), it->sprite);
                rl.push_back(a);
            }
 
            mainRenderer.Update(rl);
            // Sleep a bit so updates don't run too fast
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
        }
 
    return 0;
}

Так же, VS выдает следующую инфу (скрин прикреплен).
Еще раз прошу прощения за выкладывание всего кода.
Заранее спасибо за любую помощь.

Миниатюры

Объект приходит пустым (стертым?) к for циклу. Exception thrown: read access violation. it was 0xFFFFFFFFFFFFFFFF
 



0



Возможно, вам также будет интересно:

  • С восьмьюдесятью туристами полуторастами страницами укажите ошибку
  • С каждым работа над ошибками
  • С восьмым марта с ошибками
  • С заявлением об исправлении кадастровой ошибки обратиться может
  • С восьмистами студентами ошибка в образовании формы

  • Понравилась статья? Поделить с друзьями:
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии