Sign in to follow this  

Some Questions (C++)

This topic is 2548 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

1) I assume that I am correct in thinking that if I am instantiating a class within a scope that will exit before I'm done using that instance, I need to "new" it. Is it okay/better to instantiate like the following if I will be done with that instance before the scope exits?

Thing foo = Thing();

2) I am in the habit of throwing around classes through functions using pointers to their instances rather than the actual instance. Is that good or bad?

3) When I am making lists/vectors/arrays of a class, I usually end up making them of the pointers rather than the actual instances. Again, good or bad?

4) Is it possible to create a class in which a member points to the same spot in memory in every instance, and a change in one instance to this member will result in a change throughout all instances of that member in that class? I don't mean merely having them all point to the same spot in memory, I mean they all refer to the same member object..Is this what the static keyword is for?

Share this post


Link to post
Share on other sites
Quote:
Original post by Schnozzinkobenstein
1) I assume that I am correct in thinking that if I am instantiating a class within a scope that will exit before I'm done using that instance, I need to "new" it. Is it okay/better to instantiate like the following if I will be done with that instance before the scope exits?

Thing foo = Thing();


Stack allocations like the one above are faster than heap allocations since the scope is well defined in stack allocations, and can be reused. Check this out:

#include <iostream>

using namespace std;

int main() {

{
int a;
cout << "a == " << a << ", &a == " << &a << endl;
}

{
int i = 5;
cout << "i == " << i << ", &i == " << &i << endl;
}

{
int j;
cout << "j == " << j << ", &j == " << &j << endl;
}
}





Produces this output:

a == 18165804, &a == 0021FEFC
i == 5, &i == 0021FEFC
j == 5, &j == 0021FEFC


Quote:

2) I am in the habit of throwing around classes through functions using pointers to their instances rather than the actual instance. Is that good or bad?


(Misread the question. By default C++ passes parameters by value, this means that the parameters are copied into the function. This may be a performance hit if the parameters are large objects.)

Prefer using references over pointers. Both pointers and references boil down to the same machine code, so it's a matter of preference. References are harder to make mistakes with, though:


#include <iostream>

void func1( int& p ) {
p ++;
}

void func2( int* p ) {
p ++; // Whoops, meant to do: *p ++;
}

void func3( int* p ) {
*p ++;
}

int main() {
int i = 0;
func1( i ); // Ok, i is now 1
func2( &i ); // Fail; i should be 2, but it's still 1?
func3( &i ); // Ok; i is now 2
func3( 0 ); // Boom; your program crashes
}




Quote:

3) When I am making lists/vectors/arrays of a class, I usually end up making them of the pointers rather than the actual instances. Again, good or bad?


If the class is a parent, and the container may contain instances derived from that class, then yes, this is "good." However, you may get better cache locality if you store your instances contiguously in memory.

Quote:

4) Is it possible to create a class in which a member points to the same spot in memory in every instance, and a change in one instance to this member will result in a change throughout all instances of that member in that class? I don't mean merely having them all point to the same spot in memory, I mean they all refer to the same member object..Is this what the static keyword is for?


A static pointer to a member variable?


struct Foobar {
int x, y, z;
static int Foobar::* ptr;
};

int Foobar::* Foobar::ptr = 0;

int main() {
Foobar f1, f2;

Foobar::ptr = &Foobar::x;
f1.*Foobar::ptr = 5; // f1.x = 5
f2.*Foobar::ptr = 5; // f2.x = 5

Foobar::ptr = &Foobar::y;
f1.*Foobar::ptr = 6; // f1.y = 6
f2.*Foobar::ptr = 6; // f2.y = 6
}


Share this post


Link to post
Share on other sites
1) Yes. However, better is:

Thing foo; // do this - create a single instance
// NOT
Thing foo = Thing(); // 2 instances. Thing() (first instance) which then gets copied to foo (2nd instance) (unless your compiler knows enough to optimize that)

2) Pointers are better - you send a copy of the pointer to the function instead of a copy of the entire instance. You can also use references.

3) It depends on what you're doing with the container. If you're going to copy elements of the container a lot, pointers are better. smart_ptrs are even better.

4) Yes, a static class variable is shared among all instances of that class.

EDIT: ninja'd.. and his explanations are more complete. Ah, well.

Share this post


Link to post
Share on other sites
Quote:
Original post by Buckeye
1) Yes. However, better is:

Thing foo; // do this - create a single instance
// NOT
Thing foo = Thing(); // 2 instances. Thing() (first instance) which then gets copied to foo (2nd instance) (unless your compiler knows enough to optimize that)

What if I don't want to use the default constructor? I know my example just uses it twice, but what if I don't need/want the default constructor?

Quote:
Original post by _fastcall
If the class is a parent, and the container may contain instances derived from that class, then yes, this is "good." However, you may get better cache locality if you store your instances contiguously in memory.

Arrays are good for cache locality (if I'm thinking correctly), but what should I be using for these two types of lists:
A variable-sized list with a greatly-varying size
A variable-sized list with a small-varying size (normal array for this, or is sort-of-locality in memory not worth anything?)

Quote:
Original post by _fastcallStack allocations like the one above are faster than heap allocations since the scope is well defined in stack allocations, and can be reused.

Okay, so when I'm done with this, I can just call the deconstructor like foo.~Thing(); ?

Share this post


Link to post
Share on other sites
Quote:
what if I don't need/want the default constructor?

Use the constructor you want. E.g.,

Thing foo(int someInt, float 2.3f); // or whatever arguments your other constructors require

Quote:
I can just call the deconstructor like foo.~Thing(); ?

No. Just let it go out of scope. Otherwise, the destructor will get called twice - by you, and when it goes out of scope.

EDIT: If there's some reason you don't want to let it just go out of scope, add a function to do whatever you want before the destructor is called. In the destructor, check to see if that function was already executed.

class Thing
{
public:
Thing(): unloaded(false);
~Thing() { if(!unloaded) Unload(); }
void Unload() { Unload_some_stuff; unloaded = true; }
bool unloaded;
};
//....
Thing foo;
//.....
foo.Unload();
//....
return; // foo goes out of scope and destructor is called.

Share this post


Link to post
Share on other sites
Quote:
Original post by Schnozzinkobenstein
What if I don't want to use the default constructor? I know my example just uses it twice, but what if I don't need/want the default constructor?

Then don't call the default constructor:

class Thing {
public:
Thing( int, int ) {
// Do nothing
}
};

int main() {
Thing foo1( 1, 2 );
Thing foo2 = Thing( 3, 4 );
Thing foo3; // Error, no default constructor
}



Quote:

Arrays are good for cache locality (if I'm thinking correctly), but what should I be using for these two types of lists:
A variable-sized list with a greatly-varying size
A variable-sized list with a small-varying size (normal array for this, or is sort-of-locality in memory not worth anything?)


Arrays in C++ cannot have elements of varying size, you can have an array of pointer-to-elements-of-varying-size since all pointers are of constant size.

Quote:

Okay, so when I'm done with this, I can just call the deconstructor like foo.~Thing(); ?


No, don't do that*. Destructors are called automatically:


#include <iostream>

using namespace std;

struct Thing {
static int count;
int id;

Thing() {
id = ++count;
cout << "Thing " << id << " created." << endl;
}
~Thing() {
cout << "Thing " << id << " destroyed." << endl;
}
};

int Thing::count = 0;

int main() {
delete new Thing; // Thing 1 created, thing 1 destroyed

Thing ptr;

{
Thing a1; // Thing 2 created

{
Thing a2; // Thing 3 created
ptr = new Thing; // Thing 4 created
} // Thing 3 destroyed

delete ptr; // Thing 4 destroyed
} // Thing 2 destroyed
}


(*Unless the object was called using placement-new)

Share this post


Link to post
Share on other sites
Quote:
Original post by Schnozzinkobenstein
What if I don't want to use the default constructor? I know my example just uses it twice, but what if I don't need/want the default constructor?

Then don't call the default constructor:

class Thing {
public:
Thing( int, int ) {
// Do nothing
}
};

int main() {
Thing foo1( 1, 2 );
Thing foo2 = Thing( 3, 4 );
Thing foo3; // Error, no default constructor
}



Quote:

Arrays are good for cache locality (if I'm thinking correctly), but what should I be using for these two types of lists:
A variable-sized list with a greatly-varying size
A variable-sized list with a small-varying size (normal array for this, or is sort-of-locality in memory not worth anything?)


Arrays in C++ cannot have elements of varying size, you can have an array of pointer-to-elements-of-varying-size since all pointers are of constant size.

Quote:

Okay, so when I'm done with this, I can just call the deconstructor like foo.~Thing(); ?


No, don't do that*. Destructors are called automatically:


#include <iostream>

using namespace std;

struct Thing {
static int count;
int id;

Thing() {
id = ++count;
cout << "Thing " << id << " created." << endl;
}
~Thing() {
cout << "Thing " << id << " destroyed." << endl;
}
};

int Thing::count = 0;

int main() {
delete new Thing; // Thing 1 created, thing 1 destroyed

Thing ptr;

{
Thing a1; // Thing 2 created

{
Thing a2; // Thing 3 created
ptr = new Thing; // Thing 4 created
} // Thing 3 destroyed

delete ptr; // Thing 4 destroyed
} // Thing 2 destroyed
}


(*Unless the object was called into existence using placement-new)

Share this post


Link to post
Share on other sites
Quote:
Original post by _fastcall
Quote:

Arrays are good for cache locality (if I'm thinking correctly), but what should I be using for these two types of lists:
A variable-sized list with a greatly-varying size
A variable-sized list with a small-varying size (normal array for this, or is sort-of-locality in memory not worth anything?)


Arrays in C++ cannot have elements of varying size, you can have an array of pointer-to-elements-of-varying-size since all pointers are of constant size.

I meant that the lists are varying in size. I have a tendency to use vectors a lot, and I'm wondering what the efficiently-responsible thing to do is.

Quote:
Original post by _fastcall(*Unless the object was called using placement-new)

Did you mean unless I'm using placement-delete, or am I confused about how that works? The way I understood it was I can use placement-new or placement-delete instead of new or delete but didn't have to use placement-delete if I used placement-new because I could be done with my memory now and thus just want to delete it.

Share this post


Link to post
Share on other sites

This topic is 2548 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this