views:

164

answers:

6

Hi everyone! I'm trying to write a linked queue in C++, but I'm failing so far. I've created 2 files by now: my main.cpp and box.h. When trying to use my box, I receive the following message:

Description Resource Path Location Type conversion from ‘Box*’ to non-scalar type ‘Box’ requested main.cpp /QueueApplication line 14 C/C++ Problem

My code is as follows:

box.h

#ifndef BOX_H_
#define BOX_H_

template<class T>
class Box
{
public:
    Box(T value)
    {
        this->value = value;
        this->nextBox = NULL;
    }
    T getValue()
    {
        return this->value;
    }
    void setNext(Box<T> next)
    {
        this->nextBox = next;
    }
private:
    T value;
    Box<T> nextBox;
};

#endif /* BOX_H_ */

main.cpp

#include<iostream>
#include "box.h"

using namespace std;
int main(int argc, char** argv)
{
    Box<int> newBox = new Box<int>();
    cout << "lol";
    cin.get();
    cin.ignore();
    return 0;
}

Could you guys help me?

PS: before someone ask me why not to use stl ... I'm in a data structures class.

+1  A: 

When you use new, you get a pointer to an object, not a plain object. Declare your variable as a pointer or just allocate your object on the stack instead.

I hope this makes sense to you, since if it doesn't, you should probably go back and read more about the basics of OOP in C++.

Matti Virkkunen
+2  A: 

There are multiple problems here.

First of all, in order to implement a linked list (or a queue that uses a linked list) in C++ you need to use pointers. In Java everything is a reference. C++, on the other hand, makes a clear distinction between objects and pointers to objects. (There are also references to objects, but they are irrelevant here).

Let's also forget the templates for a moment, because they are not part of the problem here.


class Box
{
  int value;
  Box nextBox;  // wrong! should be a pointer
};

is wrong, because nextBox must be a pointer to the next element of the list/queue. The correct way would be Box *nextBox;

By the same token setNext() should also take a pointer to Box as its argument. setNext(Box b) is an example of pass-by-value, i. e. this member function (method in Java lingo) gets its own copy of the entire Box object. This could lead to performance issues if the object is large, not to mention that any changes done to it by the function will be invisible to the caller. What you want instead here is pass-by-reference, which is accomplished by using a pointer.

The final point is that new in C++ always returns a pointer. You should have Box<int> *newBox = new Box<int>;

Dima
+4  A: 

I believe your nextBox should be a pointer.

Box<T> * nextBox;

Method setNext should deal with pointers too.

void setNext(Box<T> * next)

And newBox should be a pointer.

Box<int> * newBox = new Box<int>(); 

Since you come from a Java background, you are assuming that all of your objects are references. Syntax is a little different in C++.

Starkey
as well as the parameter to `setNext` and the local variable `newBox`.
Ben Voigt
sorry, but `this.value` will not compile, because `this` is a pointer in C++. `this->value` is correct. It doesn't mean that `value` is a pointer. It means that `this` is a pointer.
Dima
`value` isn't a pointer, but `this` is, so `this->value` is correct (if needlessly wordy)
Ben Voigt
Yup, you're right. I got rid of that. Mind fart.
Starkey
Those new versions of the interface do not take into consideration ownership of the pointers! Passing pointers like that is asking for trouble you may want to specify some smart pointer so we know who owns the pointer and thus who is responsable for deleting them.
Martin York
@Martin: you are right of course, but smart pointers are advanced stuff. IMHO, if you are learning data structures in C++, you should first do it with raw pointers. Then, after you fall into all the traps, you can move on to smart pointers.
Dima
@Dima: I believe the exact opposite. It is simpler to learn using smart pointers.
Martin York
@Martin: To each his own, I guess. Incidentally, with a bit of tweaking this queue can be implemented without any smart pointers, but in such a way that raw pointers are never passed around. :)
Dima
@Martin: that's the point, it's simpler to learn using smart pointers. But then you don't fully understand what's going on. It's exactly the reason that we get so many questions from people coming from java not knowing that `new` is used differently
Falmarri
+4  A: 

The problem is with this line

Box<int> newBox = new Box<int>();

The new operator returns a pointer to a Box object created on the heap. The pointer will be of type Box<int>*. The left side of that expression declares a Box object. You can't directly assign a pointer-to-X to an X. You should probably just omit the new keyword unless you have a reason to want to manage the storage lifetime of the object manually. Incidentally, I'm betting you come from Java, where new is always required to create objects. Not so in C++.

Also I think it's awesome that your data structures class is introducing you to templates right off the bat.

Tyler McHenry
To make a queue from a linked list, it is appropriate to have dynamic allocation via operator `new`.
Ben Voigt
But it doesn't introduce templates. Professor said "Choose the language you want", so everyone else keeps programming in java (which is way easier) and I chose C++ ... because C++ is C++. I want to work with games, so you get my point.
Bruno
Well then it's awesome that you dove right into using templates when learning C++ (and seem to be using them properly!)
Tyler McHenry
Themplates are one of the hardest concepts in C++ (imo) and you seem to have gotten it fairly correct. You should take a look at allocating objects on the heap versus the stack. I normally say sit down with a beginning C++ book, but most people's code that I say that is very poor =]
Falmarri
Templates are very deep. As used here, for generic programming, they are not hard at all. Start adding specializations, compile-time metaprogramming, helper classes for automatic conversions -- that's where the complexity lies.
Ben Voigt
+4  A: 

Removing unimportant stuff, we see you've declared a new class like this:

template<class T>
class Box
{
    T value;
    Box<T> nextBox;
};

How big is Box<T>?

Clearly

sizeof Box<T> >= sizeof(Box<T>::value) + sizeof(Box<T>::nextBox)
sizeof Box<T> >= sizeof(T) + sizeof(Box<T>)
0 >= sizeof (T)

uh-oh

Ben Voigt
That is really cool!
Dima
A: 

Guys. No raw pointers in C++ unless you really need them. Please. Especially for some poor soul who doesn't even know that operator new returns a pointer. Get a std::auto_ptr or a std::shared_ptr.

DeadMG
This apparently isn't production code, but a learning exercise. In which case raw pointers are totally appropriate.
Ben Voigt
Completely irrelevant to the question. I agree with Ben.
mathepic
A very good answer, `+1`. I have seen many C++ programmers who first learned to do manual memory management and never got around unlearning this and learning to do things the right way, writing poor, error-prone, and often-crashing applications. __Teach people to do it the right way from lesson one.__ For many years I have taught C++ and my students saw their first `std::vector` during the 2nd or 3rd lesson, but `new` and `delete` they only saw around the 10th. Have a look at http://www.acceleratedcpp.com. It taught me how to teach better and how to write better. (And I was doing TMP by then.)
sbi
Thanks, sbi. @Ben: Awesome, so he can learn to write memory leaks.
DeadMG
@sbi: vector isn't a smart pointer. @DeadMG: I didn't vote you down, but `std::auto_ptr` is as dangerous as a raw pointer, in much more subtle ways. Learning how to manage object lifetimes is essential, and smart pointers don't solve that problem, they just prevent the memory from outliving the object.
Ben Voigt
@Ben: It manages a dynamically allocated array; smart pointers, `std::vector`, `std::string`, `std::fstream` etc. are all RAII classes, managing resources. Anyway, my point was that, before Koenig/Moo came along, practically everybody thought you cannot teach students how to use `std::vector` before they have learned to write their own classes, dealt with manual memory management, and understood templates. Certainly that's not true, but some still cling to this style of teaching. My students learned about smart pointers the lesson they learned about `new`. by then they already knew about RAII.
sbi
@DeadMG: I agree about `std::auto_ptr` being a beast with subtle dangers. I think `std::scoped_ptr` is better. But then, the current standard only knows `std::auto_ptr`, so while not perfect, your answer is at least not wrong.
sbi
@sbi: `std::vector` *owns* an array. Smart pointers reference dynamically allocated objects, but conceptually they don't (always) own them, which is what leads to complexity. Also, while it isn't necessary to be able to recreate `std::auto_ptr` in order to use it, I think unless you first teach what the library is doing on your behalf, it's impossible to reason about it. Now, many students prefer to learn by rote, but they end up unable to apply their knowledge if the problem changes in any non-trivial way.
Ben Voigt
I would suggest that before students learn dynamic allocation with either raw or smart pointers, they should learn to solve bounded problems using a static array. First, iterate across fixed data sets. Then, add an "element in use" flag and show a linear search to find an unused element. Then a free pool to avoid the linear search. Also a FIFO queue in a circular buffer where no linear search is required. Then change the free pool implementation to use real pointers. Maybe add a non-template smart pointer to automatically return items to the free pool. Now the std allocator makes sense.
Ben Voigt
OTOH, understanding the machine is really only helpful when making reusable software. But for those who just need some programming ability to automate simple tasks in a one-off fashion, I would question the need for any memory management. It's more cost-effective (on projects for one's own use) to buy 16GB of RAM than to study dynamic deallocation. But for those projects C++ isn't really appropriate anyway -- Javascript or MatLab or Python would be better. The extra effort for learning and writing in C++ pays off only when the code is reused. Efficiency of a single run hardly matters.
Ben Voigt
@Ben: The key-concept, _life-time management_, is shared between `std::vector`, `std::shared_ptr`, and the rest I mentioned. You can draw a (very fine) line between RAII classes like `std::vector`, which also _allocate_ the resource they manage, and those like `std::shared_ptr`, which don't, but they key concept, _deletion in a dtor_ is the same to all of them. (Stroustrup himself had once, in a c.l.c.m discussion, said that RAII is a misnomer, because it's not the ctor which should get the attention, but the dtor.)
sbi
Further, I have _very_ good experience with students _using_ RAII classes without being able to explain what's going on under the hood. When you think of it, this is the state of affairs in many other languages. Come to think of, C's and C++' ability to implement their own standard library _within the language_ rather stands out from the crowd. So programmers are _used_ to treat types like `string` as magic boxes. They do it in so many other languages. It's fine. The fact that `std::string` is _implemented_ in C++, is an additional bonus, and understanding that code requires quite an...
sbi
...understanding of the language - which will only be achieved long after the ability to _use_ `std::string`. (Substitute `std::shared_ptr` for `std::string` if you disagree. [A good smart pointer is surprisingly hard to write.](http://stackoverflow.com/questions/1437053/1437748#1437748)) As I said, I read _Accelerated C++_ when I had been programming in C++ for years, had taught it for a while, and had delved into template-meta programming. Yet it changed the way I saw the language to be taught and used. I can wholeheartedly recommend the experience to any seasoned old-school C++ programmer.
sbi
I know a complete smart pointer is very hard to write. One that completely meets the needs of any single application, not so hard at all. But while I don't think someone needs to be able to duplicate `std::auto_ptr` to use it effectively, I do think that concepts such as that freeing the memory causes the block to be added to a free list are essential to understanding why double-freeing is bad, etc., irrespective of whether that free routine is called manually or by the destructor of a smart pointer.
Ben Voigt
@Ben: I agree that students need to understand why they need a smart pointer (because in C++ memory must be freed explicitly). However, I don't see why, for novices, this must exceed a chalkboard demonstration. We shouldn't deal with memory manually (I certainly didn't do it during the last decade) and my philosophy in teaching was to never teach the students to do anything that they had to unlearn later. When students are more fluent with the language, they should, in principle, be able to write their own string class, smart pointer or similar.
sbi
However. Did you follow that link? I've seen numerous home-grown smart pointers. They all started out as tools needed for one application, and they all ended up in the company's tool box. And they all had bugs.
sbi
To a student who hasn't seen even a trimmed-down smart pointer implementation, an object being freed too early because of misusing the smart pointer is utterly indistinguishable from a bug in the smart pointer. I submit to you that the students who are making "good" use of smart pointers without understanding how they work would be better served by not freeing memory at all, since the time saved is likely worth more than the cost of an extra 16GB of RAM.
Ben Voigt
Only students with a future designing software with long runtime or for repeated use need to worry about memory management, and they had better not only learn to use smart pointers but how to reason about them grounded in a solid understanding of what techniques are used by the implementation.
Ben Voigt
Most cases of one-off development where running out of memory would be a problem are iterative in nature and actually best solved not by smart pointers that free the memory so it is available for reuse, but by a ping-pong scheme where there are two generations stored: the existing data and the one being computed, and at the end of each iteration the two are simply exchanged. This gives higher performance than using smart pointers in just about every way (lower memory use, less time spent allocating, better data locality, etc) and isn't harder than smart pointers, just a different approach.
Ben Voigt