Jump to content
  • Advertisement
Sign in to follow this  
valsar

Question about objects(classes)

This topic is 4058 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a question about declaring objects. example: Class Player { protected: int x, y }; I know that you can use Player myPlayer to declare an object for type Player. but I've also seen myPlayer = New Player (or something like that). What's the difference between the two? I know the second one you have to use delete(myPlayer) to free up the memory but that's about it. Is the second even a way to declare an object from a class?

Share this post


Link to post
Share on other sites
Advertisement
The second way is a way to dynamically create an object an obtain a pointer to it. You probably are not familiar with pointers, so you should read on them and your questions will probably be answered.

Share this post


Link to post
Share on other sites
Here are some very 'beginner' terms to summarize the idea:

If you say:


// C++ only.
Player myPlayer;


Then myPlayer only exists as long as the current function is running. After the function finishes, myPlayer is "destructed" (it is cleaned up - any memory it was using is recycled for other uses). It's kind of like saying 'myPlayer' exists INSIDE that function.


If you say:


// C++
Player *myPlayer = new Player();

// C#
Player myPlayer = new Player();


Then myPlayer is created OUTSIDE your function, and it doesn't automatically get cleaned up when your function exits! If you aren't careful, and forget to clean it up yourself, this is what they call a memory leak.

Because in this case myPlayer exists outside the function, other functions could potentially access it if you pass the pointer between functions.


To clean up something that is created the second way, do this:


// C++
delete myPlayer;

// C#: The language cleans it up automatically - you don't need to do anything.



In actual practice there are more details that you will eventually need to know, but this should get you a little more familiar with it.

Share this post


Link to post
Share on other sites
Every program started gets a limited amount of memory assigned to it by the OS.
This potion of memory is quite small and is usually refered to as the program stack.
When you declare a variable like this
Player myPlayer;
The myPlayer object is placed on the stack.

If you declare the obect like this
Player* myPlayer = new Player;
or
Player* myPlayer = (Player*)malloc(sizeof(Player));
The myPlayer object (or rather the Player object this pointer refers to) is placed on the heap.
The heap is, in short, all the currently free memory on your computer, and is much larger than the program stack.

Huge objects like images, sound, video etc. is usually too big for the program stack, and must be allocated on the heap.

Share this post


Link to post
Share on other sites
Quote:
Player* myPlayer = (Player*)malloc(sizeof(Player));


This allocation method is only possible for POD types, and is never used in C++ anyway.

Share this post


Link to post
Share on other sites
Thats right.
I guess I was influenced by the relentless use of malloc in C++ programs out there. Im not even sure if the OP is talking C++ at all.

Share this post


Link to post
Share on other sites
Quote:
Original post by pulpfist
Im not even sure if the OP is talking C++ at all.


The protected: label exists in only one mainstream language, C++ [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Quote:
Player* myPlayer = (Player*)malloc(sizeof(Player));


This allocation method is only possible for POD types, and is never used in C++ anyway.


Wrong. Herb Sutter uses a method like above in Exceptional C+ + to create an array of objects without the need of the objects' class to have a default constructor and an assignment operator. You can, indeed, allocate memory like above (but you'd better use ::operator new). That does not execute constructors, but sometimes it may be desired.



#include <memory>
#include <iostream>
#include <iterator>
#include <algorithm>

class A
{
public:
explicit A(int val) : val(val) { std::cout << "A::A()" << std::endl; }
~A() { std::cout << "A::~A()" << std::endl; }
std::ostream &print(std::ostream &os) const { return os << "A(" << val << ")" << std::endl; }
private:
int val;
};

std::ostream &operator<<(std::ostream &os, const A& a)
{
return a.print(os);
}

int main()
{
const size_t size = 3;

#if 0
A objects[size]; // does not work, requires default constructor
for(size_t i = 0; i < size; ++i) objects = A(i); // works, but requires assignment operator
#endif

std::cout << "Allocate" << std::endl;
A *ptr = static_cast<A*>(::operator new(size * sizeof(A)));

std::cout << "Construct" << std::endl;
for(size_t i = 0; i < size; ++i)
{
/* Warning: if A::A() may throw exceptions, resources will leak. In practice this would be handled. */

new (ptr + i) A(i); // placement new, creates new A into memory at ptr + i
}

std::cout << "Use" << std::endl;
/* Again, a risk for corruption if an exception occurs! Handle it! */
std::copy(ptr + 0, ptr + size, std::ostream_iterator<A>(std::cout));

std::cout << "Destruct" << std::endl;
for(size_t i = 0; i < size; ++i)
{
(ptr + i)->~A();
}

std::cout << "Deallocate" << std::endl;
::operator delete(ptr);
}



As a guideline, you should always avoid allocating memory from the heap (something = new Something(params); ). Most allocations can be replaced with stack allocation and/or using standard containers. If you must allocate something, then you should always use a smart pointer (such as std::auto_ptr or boost::shared_ptr).

In other words:

Player myPlayer(params); // if possible
Player *myPlayer = new Player(params); // a no, no! never do this
std::auto_ptr<Player> myPlayer(new Player(params)); // use this if possible (myPlayer has single owner)
boost::shared_ptr<Player> myPlayer(new Player(params)); // if the above doesn't suffice, do this

Player players[size]; // if possible
Player *players = new Player[size]; // just don't
std::vector<Player> players; // better


If your Player class is noncopyable (private copy constructor and operator=) or it's not practical to copy Players (objects are large, etc), then you can't use fixed arrays or standard containers.


Player *players[size]; players = new Player(params); // nope, not like this
std::vector<Player*> players; players.push_back(new Player(params)); // not like this either
std::vector<std::auto_ptr<Player> > players; // nope, you can't put auto_ptrs in a container
std::vector<boost::shared_ptr<Player> > players;
players.push_back(boost::shared_ptr<Player>(new Player(params))); // this is better
boost::ptr_vector<Player> players; players.push_back(new Player(params)); // this works too


Links:
http://www.boost.org/libs/smart_ptr/smart_ptr.htm
http://www.boost.org/libs/ptr_container/doc/ptr_container.html

Always prefer smart pointers to pointers. It is possible to write safe code using new and delete, but it needs a lot of careful planning and extra cleanup code. You should also prepare yourself for exceptional situations and write code that doesn't leak resources if exceptions occur (basic exception safety). This requires even more care.

Many people (especially in the games industry) avoid standard containers and boost. Just ignore that bunch of people and familiarize yourself with the c++ standard library and boost libraries. Usually those who don't use boost or stdlib waste their time rewriting similar features.

-Riku

Share this post


Link to post
Share on other sites
Quote:
Original post by riku
Quote:
Original post by ToohrVyk
Quote:
Player* myPlayer = (Player*)malloc(sizeof(Player));


This allocation method is only possible for POD types, and is never used in C++ anyway.


Wrong. Herb Sutter uses a method like above in Exceptional C+ + to create an array of objects without the need of the objects' class to have a default constructor and an assignment operator. You can, indeed, allocate memory like above (but you'd better use ::operator new). That does not execute constructors, but sometimes it may be desired.


You're right, my wording was somewhat confused. The idea is that the proposed allocation method is not possible (in a way that is sensibly equivalent to using one form of new Player) for any non-POD type. It does, of course, allocate memory for a Player object and return a pointer to it in a perfectly defined way, even if the C++ version would still not be the above, but rather:

reinterpret_cast<Player*>( ::operator new(sizeof(Player)) );

EDIT: also, an alternative to the casting and a way to make your copy-constructible objects assignable and that I like very much is:


template<typename T>
class Assignable
{
char data[sizeof(T)];
T* ptr;
public:

// Typical constructors and destructors.
Assignable() : ptr(0) {}
~Assignable() { if (ptr) ptr->~T(); }
Assignable(const Assignable & o) : ptr(0)
{ if (o) ptr = new (data) T(*o); }
Assignable(const T & o) : ptr (0)
{ ptr = new (data) T(o); }

// Create assignment using copy-construction.
// If copy constructor throws, results in "null" object.
Assignable & operator=(const Assignable & o)
{
if (&o == this) return *this;
if (ptr) ptr->~T();
ptr = 0;
if (o) ptr = new (data) T(*o);
return *this;
}

Assignable & operator=(const T & o)
{
if (ptr) ptr->~T();
ptr = 0;
ptr = new (data) T(o);
return *this;
}

// Represents nullity of the object
void* operator void*() { return ptr; }

// Look like a pointer.
T& operator*() { assert (ptr); return *ptr; }
const T& operator*() const { assert (ptr); return *ptr; }

// And so on.
};



It's nice, because it doesn't use any casts.

[Edited by - ToohrVyk on May 12, 2007 7:17:25 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!