0

Background:
I have created a player class and I want to ask the user how many players are going to play the game? Based on the user input I am trying to create that many instances of the player class. However, I used the following links to help me:
Create object using user input
http://www.cplusplus.com/forum/beginner/197342/
So, I tried their solution:

#include "Player.h"

int main() {

    int totalPlayers = -1;
    cout << "Enter total number of players: ";
    while ((totalPlayers < 1) && (totalPlayers > 5)) {
        cout << "How many players will be playing? (1-5): ";
        cin >> totalPlayers;
    }
    vector<Player> players(totalPlayers);

    system("pause");
}    

I get the error: Unhandled exception at 0x763F40B2 in 16LinearChess.exe: Microsoft C++ exception: std::length_error at memory location 0x003BF690.
So, I googled this exact error and found this link: Error : std::length_error at memory location
So, firstly his code was no-where related to mine, but the error was same. I did not understand the answer, but I thought that I had to create the instances using heap memory. So I tried that:

#include "Player.h"

int main() {

    int totalPlayers = -1;
    cout << "Enter total number of players: ";
    while ((totalPlayers < 1) && (totalPlayers > 5)) {
        cout << "How many players will be playing? (1-5): ";
        cin >> totalPlayers;
    }
    vector<Player> *players = new Player(totalPlayers);
    delete[] players;

    system("pause");
}    

I got two errors:
Severity Code Description Project File Line Suppression State Error (active) E0144 a value of type "Player *" cannot be used to initialize an entity of type "std::vector<Player, std::allocator> *" 16LinearChess D:\Keshav\Programming Languages\C++\Beginner\01 Michael Dawson\16LinearChess\LinearChess.cpp 64


Severity Code Description Project File Line Suppression State Error (active) E0289 no instance of constructor "Player::Player" matches the argument list 16LinearChess D:\Keshav\Programming Languages\C++\Beginner\01 Michael Dawson\16LinearChess\LinearChess.cpp

This is my Player class:

#include <iostream>

class Player : public Board {
protected:
    int m_position;
    Log logger;
    int m_playerNumber;
public: 
    static int m_numberOfPlayers;
    Player() :m_position(0) {
        ++m_numberOfPlayers; 
        m_playerNumber = m_numberOfPlayers;
    }

    void m_SetPlayerPosition(int &position) {
        if ((position < 0) || (position > 100)) {
            m_position = 0;
            logger.Error("Position cannot be less than or greater than 100. Your position has been reset to 0 because you fell out of the map.");
        }
        else {
            m_position = position;
        }
        m_SetBoardPosition(m_position, m_numberOfPlayers); // update the position on the board.
    }

    friend ostream &operator << (ostream &os, Player &player) {
        os << "Player position on board: " << player.m_position << "\nPlayer Number: " << player.m_playerNumber << '\n';
        return os;
    }
};

int Player::m_numberOfPlayers = 0; // initializing total number of players.

Thank You!

Programming Rage
  • 403
  • 1
  • 4
  • 18
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/220062/discussion-on-question-by-programming-rage-create-player-objects-based-on-the-nu). – Samuel Liew Aug 19 '20 at 02:47

2 Answers2

4

The problem is with your while loop:

    int totalPlayers = -1;
    cout << "Enter total number of players: ";
    while ((totalPlayers < 1) && (totalPlayers > 5)) {
        cout << "How many players will be playing? (1-5): ";
        cin >> totalPlayers;
    }

The while loop will only run if the condition is true, but the condition can never be true since no number can be smaller than 1, but also greater than 5. And since the condition is not true, the while loop will never run, and totalPlayers will be equal to -1, which is something you never want if you're trying to access an array index.

Change it to this: totalPlayers < 1 || totalPlayers > 5 with an || instead, and you should be fine.

And for the error:

Unhandled exception at 0x763F40B2 in 16LinearChess.exe: Microsoft C++ exception: std::length_error at memory location 0x003BF690.

Your code threw an exception because totalPlayers is equal to -1. So you basically did this:

vector<Player> players(-1);

Which makes no sense since you are creating an array that hold -1 elements? So the code threw an exception telling you that something is wrong. The std::length_error should give a hint about what's wrong.

Also like many of the comments have stated, don't do this:

vector<Player> *players = new Player(totalPlayers);

The whole purpose of a vector is so you don't do that. Your first example works fine:

vector<Player> players(totalPlayers);
Alex
  • 462
  • 1
  • 7
  • 19
  • Ok so if -1 wraps around to the largest unsigned int value, why does it not create that many instances then? To prevent some memory problem? – Programming Rage Aug 18 '20 at 17:56
  • it doesn't. you stored `-1` to an int variable. int variable can store negatives. if you stored it in an `unsigned int` on the other hand... – Alex Aug 18 '20 at 17:58
  • @user4581301: But you had a different contribution which was much more valuable to be honest good sir. – Programming Rage Aug 18 '20 at 17:59
  • or if you're talking about the passing it to the vector, then it wouldn't create too many instances because a vector can only hold so many elements – Alex Aug 18 '20 at 18:00
  • @DynamicSquid but Human-Compiler says that it will wrap to the highest unsigned int value in his answer. – Programming Rage Aug 18 '20 at 18:00
  • `std::size_t` is guaranteed to be able to express the maximum size of any object (including any array) in C++. This means the bounds for the largest object is finite in the language. The `size_type` on containers must, similarly, be able to represent the largest size in that container; but for any type where `sizeof(T)` is larger than `1`, the max number of representable objects must also accordingly be less than the max value `size_t` can hold. This means that there are some lengths of sequences that fundamentally cannot be addressed at all -- hence `length_error` catches this early – Human-Compiler Aug 18 '20 at 18:00
  • Basically: `length_error` guards user-errors where a resize value that is requested exceeds a fundamental maximum that the container could not ever feasibly hold – Human-Compiler Aug 18 '20 at 18:01
  • `size_t` is the same as `unsigned int` – Alex Aug 18 '20 at 18:02
  • or, on visual studio at least – Alex Aug 18 '20 at 18:03
  • @DynamicSquid you mean unsigned int? If so then what is the point of having two different names? Or is there a difference? – Programming Rage Aug 18 '20 at 18:04
  • 1
    or to be more specific, it is used to represent unsigned int, unsigned long, unsigned short, etc. it's returned in places like the std::vector.size() where a generic unsigned type is used. it's a little hard to explain, but you could try reading more here: https://stackoverflow.com/questions/19732319/difference-between-size-t-and-unsigned-int#:~:text=It%20is%20a%20type%20able,specified%20by%20the%20data%20model. – Alex Aug 18 '20 at 18:06
2

std::length_error occurs if std::vector attempts to resize to a size that is above the max_size(). Most often, this happens from a bad input -- such as -1 which will be converted to the largest unsigned value for std::vector<T>::size_type.


Judging by the code you shared, the problem is actually due to your while loop condition:

    while ((totalPlayers < 1) && (totalPlayers > 5))

It is not possible for totalPlayers to be both simultaneously less than 1 and greater than 5 -- so this loop is never entered. Since the default value you assign to totalPlayers is -1, the size you resize to overflows and becomes the largest unsigned value -- which triggers the std::length_error.

Fixing this condition should fix your error.

Human-Compiler
  • 11,022
  • 1
  • 32
  • 59
  • Ooh I never know it wraps around to the largest unsigned value. But wait! If it does, should it not create the instances then? Should it not create the largest amount of possible instances? – Programming Rage Aug 18 '20 at 17:53
  • The `std::length_error` exception gets thrown if the requested size is larger than `std::vector::max_size()`. Since `-1` translates to an unsigned value with all bits set, on a 32-bit system this would be a number of `2^32-1` instances (4,294,967,295 instances) -- which is most likely larger than `max_size()`. This would account for why the exception is being thrown rather than resizing – Human-Compiler Aug 18 '20 at 17:55
  • Aah so they implemented a safety-feature there! Or, you simply cannot create that many instances due to the size of one instance as it has its data members and may lead to memory leaks right? – Programming Rage Aug 18 '20 at 17:58
  • 1
    Not memory leaks, but a coarse metric that "no one" has enough memory to allocate an array that big. Leak is when you ask for a resource (file, block of memory, a horse), you get it, (which did not happen in your failure case) and you don't put it away when you are done so no one can find it if they need it again. It's like when your brother doesn't put the screwdriver back. You either have to get a new screwdriver or abandon the job that required the screwdriver. – user4581301 Aug 18 '20 at 18:09
  • 1
    Note you can often request far, far more storage than you actually have. Most modern operating systems will allow you to have memory, but not give it to you until you actually use it. And even then they may only give you the little bit you just used. It's possible to successfully get a Zounds... big array and then crash later when the OS can't provide the promised memory. In the meantime when it runs out of RAM, [it could start using anything else it can use for storage, like the hard drive](https://en.wikipedia.org/wiki/Paging). – user4581301 Aug 18 '20 at 18:19