1

In C++, I'm having trouble with pointers etc. How can I fix the following problem?

error: no match for 'operator=' in '(stage->Stage::tiles + ((unsigned int)(((unsigned int)t) * 12u))) = (operator new(12u), (, ((Tile*))))'| note: candidates are: Tile& Tile::operator=(const Tile&)|*

stage.h

#include "Tile.h"

class Stage {
    public:
        Tile *tiles;
        int size;
        void init(int size);
};

stage.cpp

void Stage::init(int size) {
    this->size = size;
    this->tiles = new Tile[size];
}

application.cpp

#include "Stage.h"
#include "Tile.h"

bool setTiles( Stage * stage ) {

    for( int t = 0; t < stage->size; t++ ) {
        stage->tiles[t] = new Tile();
    }

    return true;
}

stage.init(1234);
setTiles( &stage );

Also, I don't really know when to use object.attribute and when to use object->attribute?

Ben
  • 15,938
  • 19
  • 92
  • 138
  • `Stage` doesn't have a member variable called `size`. Please post your *actual* code. – Oliver Charlesworth Aug 19 '11 at 13:07
  • Sorry, I made this version particularly so that its easier to understand. Fixed it now. – Ben Aug 19 '11 at 13:10
  • 2
    Recovering Java programmer? If you just want `tiles` to be an array of tiles, you don't have to do anything beyond `new Tile[size]` -- that already invokes the default constructors for every element in the array. The entire `setTiles` function as you wrote it seems to be unnecessary. – Kerrek SB Aug 19 '11 at 13:12
  • 2
    **Please use `std::vector`!** You will save yourself *a lot* of hassle! – Ferdinand Beyer Aug 19 '11 at 13:13
  • @Ferdinand Beyer- and if a dependency on Boost isn't an issue, take it a step further and use boost::ptr_vector. – MarkD Aug 19 '11 at 14:45
  • @Ferdinand Beyer Could u give an example of using `std::vector` in this case? – Ben Aug 21 '11 at 13:30
  • @Kerrek SB That sounds awesome, however since I've now changed it to `this->tiles = new Tile*[total_tiles]` I guess it won't work anymore!? Also, I do need to pass some arguments to the constructor. – Ben Aug 21 '11 at 13:33
  • @Ben: could you please update your post accordingly, maybe add a new section? You cannot say `Tile * x = new Tile * [5];`, you would have to declare `Tile ** x;` or something like that. – Kerrek SB Aug 21 '11 at 16:09

4 Answers4

6
stage->tiles[t] = new Tile();

You're calling new on something that's not a pointer. True, tiles is a pointer to an array, however, each element of that array is NOT a pointer. In order for that work, you would need an array of pointers, or a pointer to a pointer ,such as:

Tile **tiles;

What you could also do is create a separate pointer object, allocate it, and then copy the data to your array element by using

stage->tiles[i] = *somePointer;

and then deleting the pointer afterwards to free that allocated memory. This will preserve the copy because you invoked the copy constructor.

MGZero
  • 5,812
  • 5
  • 29
  • 46
3

You are trying to allocate a pointer with a pointer to an array. Try this one:

class Stage {
    public:
        Tile **tiles;
        void init(int size);
};
Thomas Berger
  • 1,860
  • 13
  • 26
  • Where is he "trying to allocate a pointer with a pointer to an array"? – Oliver Charlesworth Aug 19 '11 at 13:08
  • @Oli Charlesworth This is actually pretty accurate (at least his fix is, his explanation isn't), read my answer. +1 – MGZero Aug 19 '11 at 13:10
  • @Oli Charlesworth: `new Tile[size]` creates a pointer to an array of `Tile` with size `elements` `Tile *tiles` is a array or a pointer to ONE `Tile` – Thomas Berger Aug 19 '11 at 13:11
  • 1
    @MGZero: Ok, but this answer is not complete (and neither is yours, actually). The assignment in `init()` needs to become `this->tiles = new Tile*[size]` – Oliver Charlesworth Aug 19 '11 at 13:11
  • He understands the problem and provides the solution, but his formulation is nonsense ;) – Ferdinand Beyer Aug 19 '11 at 13:12
  • @Oli Charlesworth you are right, i should stop hacking answers while i am on work, and do other things parallel ;) – Thomas Berger Aug 19 '11 at 13:12
  • @Thomas: The type of `new Tile[size]` is `Tile *`. – Oliver Charlesworth Aug 19 '11 at 13:13
  • @Oli Charlesworth ok I'll agree with you on that :) – MGZero Aug 19 '11 at 13:13
  • @Oli Charlesworth isnt the type of `Tile[size]` already `Tile *` and `new` returns a pointer? – Thomas Berger Aug 19 '11 at 13:15
  • @Thomas: No. `new Tile[size]` creates an array of `Tile`, and returns a pointer to the first element. – Oliver Charlesworth Aug 19 '11 at 13:17
  • @Thomas Berger: `new Tile[size]` creates a `Tile*`, `new Tile*[size]` creates a `Tile**`. – Ferdinand Beyer Aug 19 '11 at 13:17
  • Thanks for all the answers/comments. I am using `Tile **tiles;` in stage.h, `this->tiles = new Tile*[total_tiles];` in Stage::init, and `stage->tiles[t] = new Tile( x, y, tileType );` in the application. This works and its great. However, I don't really understand why it works and I keep running into problems of this or similar kind. Could you recommend any concise tutorials (as in *not* 600 page books...) particulalry about `&`, `*`, `.` or `->`, `**` and related (I'm coming from Java)? Also, could someone please show me how to deallocate all the things we've used here? – Ben Aug 19 '11 at 13:38
  • 1
    @Ben: C++ is *very* complex and as a beginner, there are many pitfalls, especially when using dynamic memory. I would strongly recommend a good book; recommendations can be found at http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list . For a basic tutorial, consider http://www.cplusplus.com/doc/tutorial/ – Ferdinand Beyer Aug 19 '11 at 13:57
1
stage->tiles[t] = new Tile();

The above is not a valid C++ code, which you are perhaps confusing with the way new is used in other language such as C#. Though new can be used to allocate dynamic memories, but assigning an object to a particular element in the dynamically created array doesn't need the new construct. In fact, the object is already created as soon as you called new Tile[size]. What you may want to do is, create an object of type Tile and assign it to a particular element in tiles.

Tile myTile;

// do something with myTile

this->tiles[0] = myTile;
Shamim Hafiz - MSFT
  • 21,454
  • 43
  • 116
  • 176
  • 1
    Well, I need to call the constructor of `Tile` with some arguments, i.e. I need to do `Tile myTile = new Tile(...)` which won't work: error: conversion from 'Tile*' to non-scalar type 'Tile' requested --- coming from Java btw :) – Ben Aug 19 '11 at 13:23
  • @Ben: I understand you had background on C# or Java :). For your case, simply use this->titles[0] = Tile(...) ;) – Shamim Hafiz - MSFT Aug 19 '11 at 13:33
0

new Tiles() returns a pointer to a Tiles instance.

Tile *tiles defines an array out Tiles, not pointers.

Start with Tile **tiles instead.

harper
  • 13,345
  • 8
  • 56
  • 105