0

I want to write a copy c'tor to my class which contains a list of shared ptrs like this:

    std::vector<std::shared_ptr<Character>> board;

If I want he copy constructor to make copies of all of the Characters, Is is enough in my copy c'tor to write the following:

Game::Game(const Game &other): dimensions(other.dimensions), board(dimensions.getRow()*dimensions.getCol()) {
    int board_size= dimensions.getRow()*dimensions.getCol();
    for (int i=0;i<board_size;++i)
    {
        this->board[i]=other.board[I];  //or *(this.board[I]=*other.board[I];        
    }
}

plus, should I write copy c'tor in Character class? Please Note I have 2 questions,

Mooing Duck
  • 56,371
  • 16
  • 89
  • 146
Daniel
  • 69
  • 5
  • 2
    The whole point of smart pointers is to avoid unnecessary and dangerous stuff, including copy constructors. If you do want a copy, why hold a pointer. – Michael Chourdakis Jun 24 '20 at 16:59
  • 1
    Depending on your member variables, you likely don't need an explicit copy constructor. The rule of 0/3/5 starts with "rule of 0". If you don't need to write copy c'tor, operator=, or destructor, then don't. – JohnFilleau Jun 24 '20 at 17:00
  • If those are your only members and sharing `Character`s is what you want, you don't need a copy constructor. If you want to copy the `Characters`, you do. – molbdnilo Jun 24 '20 at 17:01
  • 2
    Approaching this from another direction: Do you really want to copy a `Game`? I ask because short of keeping backups of game state (in which case shared ownership of `Character`s is not a good idea) I'm not seeing the need. You might want to flesh out the use case that requires copying `Game` and make sure what you are trying actually meets your requirements. – user4581301 Jun 24 '20 at 17:13

1 Answers1

3

Normally, you wouldn't copy characters, so the obvious change is simply

Game::Game(const Game &other): dimensions(other.dimensions), board(other.board) {}

Just let the vector copy itself. But since this is the default. You don't need anything custom so instead, in your class definition, just use

Game(const Game &other) = default;
Game(Game &&other) = default;

And then you know it's fast, accurate, and bug-free.


Since you say you want copies of characters, that takes a little more effort. Note that this only works if the `Character` class is not derived from.
Game::Game(const Game &other): dimensions(other.dimensions) {
    int board_size= dimensions.getRow()*dimensions.getCol();
    board.reserve(board_size);
    for (int i=0;i<board_size;++i)
    {
        board[i].push_back(std::make_shared<Character>(*other[i]));      
    }
}
Mooing Duck
  • 56,371
  • 16
  • 89
  • 146
  • But don't I need a copy c'tor for Character? – Daniel Jun 24 '20 at 17:07
  • Plus I don't want another pointer to an existing Character... I want 2 instances... – Daniel Jun 24 '20 at 17:09
  • Your old code also didn't copy characters, nor was it mentioned in the question, so I didn't realize that was the goal – Mooing Duck Jun 24 '20 at 17:09
  • Sorry for not being clear, but it doesn't make sense to put 2 pointers on same object – Daniel Jun 24 '20 at 17:13
  • @Daniel - You mean in your application or in general? Because I'd have to contest the latter. – StoryTeller - Unslander Monica Jun 24 '20 at 17:14
  • @Daniel: The only reason to have a `shared_ptr` is to have 2 pointers to the same object. In general, one shouldn't use `shared_ptr`. – Mooing Duck Jun 24 '20 at 17:15
  • 2
    If it doesn't make sense for you to have 2 pointers to the same object then you should use `std::unique_ptr` (or the object directly) instead of `std::shared_ptr` – Kevin Jun 24 '20 at 17:15
  • How could I decide which to use? – Daniel Jun 24 '20 at 17:17
  • 1
    @Daniel, if you want separate character instances, are you certain that `shared_ptr` properly describes your intent? `shared_ptr` implies there are multiple owners of a `Character` and this character will not be freed until all of the owners no longer point to it. `unique_ptr` implies only one owner, but in this case you may want to go all the way back to allowing the `vector` to own the `Character`s and get rid of pointers entirely.. – user4581301 Jun 24 '20 at 17:17
  • 1
    @Daniel Despite its name (and the term "smart pointer"), `shared_ptr` isn't really a pointer; think of it as a shared *object*. You should use `shared_ptr` when you want to share objects among several owners, not for memory management. – molbdnilo Jun 24 '20 at 17:18
  • But in collage I was told that normal pointers are messy and we should use smart ones instead (even though they only mentioned shared_ptr) – Daniel Jun 24 '20 at 17:19
  • 1
    Handy reading: [What is a smart pointer and when should I use one?](https://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one) Note that the terminology has changed since the question was asked. Use the terminology of the second answer and the ideology of the first. – user4581301 Jun 24 '20 at 17:21
  • 2
    @Daniel yes, but you need to understand the reasons why raw pointers are bad and in what conditions are bad and why smart pointers are better and what smart pointers offer. Blindly following "always use smart pointers" won't get you far. That being said I highly suspect you don't need pointers at all. Just use `std::vector` and that's it. – bolov Jun 24 '20 at 17:21
  • 1
    The issue in't with pointers; it's with what is pointed at and how that pointed at is managed. Unmanaged allocation of resources is riskier than necessary (read that as bad) Here's a long video of a presentation by Herb Sutter that goes over the ideologies and usage of smart pointers: https://www.youtube.com/watch?v=JfmTagWcqoE – user4581301 Jun 24 '20 at 17:26
  • @bolov Character is abstract and I have other classes which inherit it – Daniel Jun 24 '20 at 17:26
  • 2
    Good information. That tidbit eliminates `vector` and suggests a smart pointer is the right way to go. Now you just have to work out who is responsible for managing the `Character` (the `Character` is freed when removed from the `vector`). If it's the `vector`, `std::unique_ptr` is probably the right choice. – user4581301 Jun 24 '20 at 17:29
  • 1
    ״Now you just have to work out who is responsible for managing the Character״ How could I know? I mean I'm the programmer and I can decide... isn't that true? @user4581301 – Daniel Jun 24 '20 at 17:32
  • 1
    You can decide, but as the programmer it's on you to make the right choice or suffer the consequences. Watch the Sutter youtube video I linked above. Dude goes over the issues better than I can. My order of preference is Automatic management (no pointer at all, eliminated here by inheritance requirement), Unique pointer (One owner), Shared Pointer( multiple equal partners in ownership), raw pointer in [RAII](https://stackoverflow.com/questions/2321511/what-is-meant-by-resource-acquisition-is-initialization-raii) wrapper, raw pointer. – user4581301 Jun 24 '20 at 17:38
  • 2
    because your class is polymorphic this answer alone won't help you. You need to provide a clone interface: https://stackoverflow.com/questions/12902751/how-to-clone-object-in-c-or-is-there-another-solution – bolov Jun 24 '20 at 17:52
  • @bolov what is clone, I understand nothing now :-( – Daniel Jun 24 '20 at 18:13