Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

AuMaestro posted:

Yeah, that code won't work, because that crashes the program if I only have one element. I was working on another solution, but you brought up a point I wasn't expecting: how different is it to remove elements of a list between them being before or after?

It shouldn't crash if you only have one element, since in terms of the iterator, it's the same as a for loop. However, it will poo poo itself if you try to remove the element after actor.

AuMaestro posted:

That's plausible, but I'm not sure if I understand. If I know in the loop whether or not I need to get rid of someone, how does that help me actually keep that iterator from going bad?

Something like this:
code:
list<Actor *>::iterator ci = actorList.begin();
Actor *actor;
while(ci != actorList.end())
{
	actor = *ci;
	if(actor->act() | actor->maintain()) // NOT short-circuiting
		ci = actorList.erase(ci);
	else
		++ci;
}
Note that this method addresses another hidden issue in your original code: if act() tried to delete the current actor, you'd segfault when you call maintain(). (Assuming you're deleting actor in addition to removing it from the list).

Avenging Dentist fucked around with this message at 03:28 on Jul 27, 2008

Adbot
ADBOT LOVES YOU

AuMaestro
May 27, 2007

Avenging Dentist posted:

It shouldn't crash if you only have one element, since in terms of the iterator, it's the same as a for loop. However, it will poo poo itself if you try to remove the element after actor.

Yeah, that kind of just moves the problem a step forward. Your second suggestion works pretty well, though I put it somewhere else (at the point where the actor is actually removed). It's a little bit of a hack, but it keeps those other methods from returning specialty bools. From there, it's just a quick fix to check to see if the iterator's at end(), and then putting it back on begin() if it is.

quote:

Note that this method addresses another hidden issue in your original code: if act() tried to delete the current actor, you'd segfault when you call maintain(). (Assuming you're deleting actor in addition to removing it from the list).

Good catch. I added an if (actor), maintain() test. Thankfully, if this all works, I'll never have to touch this code again (and I didn't even get into the fact that the actorList can be entirely replaced at any time, which means I have to check after act and maintain and break if that happens). I'm really thankful for your help.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

AuMaestro posted:

Good catch. I added an if (actor), maintain() test. Thankfully, if this all works, I'll never have to touch this code again (and I didn't even get into the fact that the actorList can be entirely replaced at any time, which means I have to check after act and maintain and break if that happens). I'm really thankful for your help.

Careful. If your code is still assigning actor the way it is currently, deleting it will have no effect on the value of actor. It'll just point to freed memory.

Depending on how you want the deletion to behave (re: deleting something before/after yourself), a more robust solution may be to simply flag actors for deletion in act() and maintain(), and then in a second loop, iterate over actorList again and delete everything that's been flagged.

Avenging Dentist fucked around with this message at 03:44 on Jul 27, 2008

AuMaestro
May 27, 2007

Avenging Dentist posted:

Careful. If your code is still assigning actor the way it is currently, deleting it will have no effect on the value of actor. It'll just point to freed memory.

Darn it, I was about to mouth off about how everything's so wrapped up in everything else that whatever it was would have of course been reassigned, but obviously that actor variable is local and won't change by itself. Thanks again. It gave me a little bit of a quiz, but I guess if I say if (actor == *ci), that'll skip it if anything funny is going on.


quote:

Depending on how you want the deletion to behave (re: deleting something before/after yourself), a more robust solution may be to simply flag actors for deletion in act() and maintain(), and then in a second loop, iterate over actorList again and delete everything that's been flagged.

That's actually what I do with the actual deletion of the object, since having it delete itself won't work.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.
I always use this pattern, even when I don't have to - easier to be supersafe than to keep track of which classes support deleting while iterating and which don't. (I mean container classes in general, not just STL.)

code:
list<Actor *>::iterator ci;
Actor *actor;
list<Actor *> actorsToDelete;

for (ci=actorList.begin();ci != actorList.end(); ++ci)
{
  actor = *ci;
  actor->act();
  actor->maintain();

  if (wantToDelete) actorsToDelete.push_back(actor);
}

// clean out everything flagged for deletion
for (ci=actorsToDelete.begin(); ci != actorsToDelete.end(); ++ci)
{
  actorList.remove(*ci);
}
Since we're iterating over actorsToDelete, removing things from actorList doesn't affect the iterator, and then actorList goes out of scope and gets cleaned up.

floWenoL
Oct 23, 2002

JoeNotCharles posted:

Since we're iterating over actorsToDelete, removing things from actorList doesn't affect the iterator, and then actorList goes out of scope and gets cleaned up.

Too bad it's unnecessarily O(n2). :psyduck:

Tetrad
Nov 3, 2002
Instead of doing something like this:
code:
for (ci=actorsToDelete.begin(); ci != actorsToDelete.end(); ++ci) { actorList.remove(*ci); }
You can do this instead (at least with STL containers):
code:
actorList.erase( std:remove_if( actorList.begin(), actorList.end(), &NeedsRemoval), actorList.end() );
Where NeedsRemoval is, of course, a function that determines whether or not the actor should be removed. Alternatively you could simplify it even more by making that function just a null check and just delete the actor and set the pointer in the container to NULL in the first loop.

Tetrad fucked around with this message at 22:24 on Jul 27, 2008

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
std::list has a member function that does that:
code:
actorList.remove_if(NeedsRemoval);
edit: copy/paste errorfest

Mustach fucked around with this message at 23:24 on Jul 27, 2008

TheSleeper
Feb 20, 2003

floWenoL posted:

Too bad it's unnecessarily O(n2). :psyduck:

Uh, you mean O(2n), no? The absolute max here is that it iterates the entire list twice I'm not seeing where it can loop n2 times.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
Nevermind what I had here before.

It's O(n^2) because remove is O(n)

floWenoL
Oct 23, 2002

TheSleeper posted:

Uh, you mean O(2n), no? The absolute max here is that it iterates the entire list twice I'm not seeing where it can loop n2 times.

Well okay if you have magical linked list where .remove() is O(1).

TheSleeper
Feb 20, 2003

floWenoL posted:

Well okay if you have magical linked list where .remove() is O(1).

What you don't?

p.s. I'm an idiot.

crazypenguin
Mar 9, 2005
nothing witty here, move along

TheSleeper posted:

p.s. I'm an idiot.

Getting .erase() and .remove() mixed up is hardly idiotic. It's just the downside to not using Javaesque names like .removeByIterator() and .removeByValue()

Zombywuf
Mar 29, 2008

Avenging Dentist posted:

Does anyone here know if anything has happened lately with the extensible literals proposal for C++0x? (I'm looking at you, TTS.) I feel like I'm the only one looking forward to it, just because it would allow the following:

code:
tuple<T0,T1,T2,T3,T4> tup;

// Old way:
tup.at<1> = T1("woop woop");
// New way:
tup[1c] = T1("woop woop");

I want the ability to write binary constants.

Lexical Unit
Sep 16, 2003

So I want to know how y'all feel about this approach.

I need to Intern some Atoms in my program. You do this just once, it's like an initialization step. So we need to know beforehand which Atoms should be interned, and then we need to be able to reference these Atoms by name, but only this predefined list of Atoms should be able to be referenced.

After we have the enumeration of available Atoms, we need to then intern them, and in doing so we obtain their Atom values. An Atom value is just an integer value that is determined at runtime.

Then we can generate a mapping from Atom name to Atom value, and whenever a user wants a particular Atom value, he just looks it up by name in the map. Except we don't want the map to go from string Atom name to integer Atom value. We don't want that because we want to restrict the valid key values to only those Atom names which have been interned, not an arbitrary string.

So here goes:
code:
#define STRINGIFY(x) #x
#define EXPAND_AND_STRINGIFY(x) STRINGIFY((x))

bool is_paren(char c)
{
	return (c == ')' || c == '(');
}

std::string remove_parens(std::string &str)
{
	str.erase (std::remove_if (str.begin (), str.end (), is_paren), str.end ());
	return str;
}

#define AVAILABLE_ATOMS
	_NET_WM_STATE,		\
	_MOTIF_WM_HINTS,	\
	WM_NAME
//	Real list is longer, and might need to grow at some later time...

// Get enum values for all the available atoms. We will use this as
// the map key so that we don't have a string as the key, which would be bad.
enum available_atom
{
	AVAILABLE_ATOMS
};

class available_atoms : private std::map<available_atom, Atom>
{
  public:
	static available_atom* instance(Display* display)
	{
		if (!single.count (display))
		{
			available_atoms* new_available_atoms = new available_atoms (display);
			single.insert (std::make_pair (display, new_available_atoms));
		}
		return single[display];
	}

	const Atom& get(available_atom atom) const
	{
		return const_cast<const Atom&> (
			const_cast<available_atoms*> (this)->operator[] (atom));
	}

  private:
	available_atoms();

	// not copyable, not assignable
	available_atoms& operator=(const available_atoms&);
	available_atoms(const available_atoms&);

	typedef std::map<available_atom, Atom> base;

	static std::map<Display*, available_atoms*> single;
};

std::map<Display*, available_atoms*> available_atoms::single;

available_atoms::available_atoms(Display* display)
{
	// Get list of atoms as a string (note that we add a '(' and ')' to the string)
	char atom_names[] = EXPAND_AND_STRINGIFY (AVAILABLE_ATOMS);

	std::vector<const char*> names_strs;
	std::list<std::string> names;
	for (char* line = strtok (atom_names, ","); line != 0; line = strtok (0, ","))
	{
		std::string name = line;
		trim (name); // just remove whitespace
		names.push_back (remove_parens (name));
		names_strs.push_back (names.back ().c_str ());
	}

	// Intern all Atoms at once
	std::vector<Atom> atoms (names_strs.size ());
	atoms.resize (names_strs.size ());
	Status status = XInternAtoms (
		display,
		const_cast<char**> (&names_strs.front ()),
		names_strs.size (),
		False,
		&atoms.front ()
	);

	if (!status)
	{
		throw an_error (display);
	}

	// Generate the map now
	available_atom atom_enum_value = static_cast<available_atoms> (0);
	for (std::vector<Atom>::iterator i = atoms.begin (); i != atoms.end (); ++i)
	{
		base::insert (std::make_pair (atom_enum_value, *i));
		atom_enum_value = static_cast<available_atom> (atom_enum_value + 1);
	}
}
So then in the client code we have a singleton for every display that allows users to get references to the Atom values they might need, but only those Atoms which are interned (ie: only those Atoms which are enumerated as available_atom values).

The only thing I don't like is the code that generates the map. Basically I'm iterating over the values in the enum, but it feels kind of hackish. Comments? Suggestions? Disapprobations?

Lexical Unit fucked around with this message at 18:56 on Jul 28, 2008

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
So, I was looking at the code in the coc'dest thread and didn't understand what was going on.

The constructor, cool, has a colon and some stuff after it. How is that different from saying p2 = c++; p1 = c; on seperate lines inside the constructor?

Edit: For bonus points, please explain the difference between assignment and initialization.

Lexical Unit
Sep 16, 2003

http://www.gidforums.com/t-7134.html

Assignment is when you call operator=(), initialization is a constructor.

Also, the code would produce the wrong output if you did as you say, and put p2 = c++; p1 = c; in the body of the constructor.

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Triple Tech posted:

So, I was looking at the code in the coc'dest thread and didn't understand what was going on.

The constructor, cool, has a colon and some stuff after it. How is that different from saying p2 = c++; p1 = c; on seperate lines inside the constructor?

http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6

Triple Tech posted:

Edit: For bonus points, please explain the difference between assignment and initialization.

drat, I can't just link to the FAQ for this. No bonus points for me.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?

Lexical Unit posted:

Also, the code would produce the wrong output if you did as you say, and put p2 = c++; p1 = c; in the body of the constructor.

Why, is it because of the order in which c is incremented? Or some other reason?

I'm still not sure I understand what the big hubbub is. The gidforums link I didn't understand at all. The parashift guy seems to point out that there's no difference for primtives. So let's make one.

If I had

code:
struct cool {
  megaObj p1, p2, p[5];
  // where the constructor for megaObj has a huge side effect
  // or takes a really long time
  
  cool(int c) : p2(c) {
    megaObj p1(c);
  }
} leet('n')
So does that mean p2 is of type megaObj without calling it's constructor? And then p1 causes the constructor to be called?

I'm not clear how this works since c is actually of type int right now... Unless int magically converts to type megaObj somewhere. Like, if the expression inside of p2 was the same as the intended type, basically the constructor would not be called?

Lexical Unit
Sep 16, 2003

In your code example you are not initializing cool::p1 with c. You are creating a new megaObj called p1, and initializing it with c. After the first line in cool's constructor, you have two megaObj's called p1. There's this->p1 (or cool::p1) and p1, they are not the same, and this->p1 is initialized by its default zero-parameter constructor.

Triple Tech posted:

Why, is it because of the order in which c is incremented? Or some other reason?
It's because in the initializer-list version of the code, c++ doesn't happen till after p1 has been initialized.

Lexical Unit fucked around with this message at 21:33 on Jul 28, 2008

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?
(Nice, btw) So what if I had said megaObj cool::p1(c) in the constructor? Would it now be the same or are there still differences?

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

Triple Tech posted:

So, I was looking at the code in the coc'dest thread and didn't understand what was going on.

The constructor, cool, has a colon and some stuff after it. How is that different from saying p2 = c++; p1 = c; on seperate lines inside the constructor?
The real reason is in 10.7:

quote:

This is because all those data members are guaranteed to have been fully constructed by the time the constructor's {body} starts executing.
That is, any constructors for member objects must be called before the body of a constructor. E.g.
code:
struct Trivial{};
struct NoArg{
  int mem;
  NoArg() : mem(17) {}
  NoArg(int z) : mem(z) {}
};
struct ArgArg{
  int mem, ory;
  ArgArg(int m, int o) : mem(m), ory(o) {}
};

struct Problem{
  Trivial t;  // has implicit trivial constructor
  NoArg n;    // has explicit no-arg constructor
  ArgArg a;   // must have arg'd constructor called in Problem's constructors
  int& i;     // must be initialized in Problem's constructors
  Problem(){} // won't compile due to the above constraints
  Problem(int x){ i = x; } // ditto
  Problem(int x) : a(3,29), i(x){} // will compile
};

quote:

Edit: For bonus points, please explain the difference between assignment and initialization.
Assignment can happen repeatedly (or never, if operator '=' isn't defined). Initialization is just that: an object is initialized at construction, like in the above example.

csammis
Aug 26, 2003

Mental Institution
e: IGNORE ME

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Triple Tech posted:

(Nice, btw) So what if I had said megaObj cool::p1(c) in the constructor? Would it now be the same or are there still differences?

Yeah, the difference would be a syntax error because that doesn't compile.

You could do "p1 = c" in the constructor (the difference is because it just says "p1" instead of "megaObj p1", it reuses the existing one instead of creating a local variable that shadows it). Then it would create p1 with the default constructor, and then call the assignment operator to update p1 with c, while the initializer list version would just call the constructor with c. If the constructor and assignment operator have side effects or are expensive, the second version is probably better.

(There's no requirement that the assignment operator even does the same thing as the constructor, so the two versions might even do completely different things. If anyone actually writes an assignment operator that does radically different things than the copy constructor, they're insane, but it's not strictly forbidden.)

StickGuy
Dec 9, 2000

We are on an expedicion. Find the moon is our mission.
Let's also not forget that initializer lists are the only way to initialize const and reference members of a class.

beuges
Jul 4, 2005
fluffy bunny butterfly broomstick
Why this:

Lexical Unit posted:

code:
#define AVAILABLE_ATOMS
	_NET_WM_STATE,		\
	_MOTIF_WM_HINTS,	\
	WM_NAME
//	Real list is longer, and might need to grow at some later time...

// Get enum values for all the available atoms. We will use this as
// the map key so that we don't have a string as the key, which would be bad.
enum available_atom
{
	AVAILABLE_ATOMS
};

instead of this:

code:
enum available_atom
{
	_NET_WM_STATE,
        _MOTIF_WM_HINTS,
        WM_NAME
};
?

MarsMattel
May 25, 2001

God, I've heard about those cults Ted. People dressing up in black and saying Our Lord's going to come back and save us all.
^^^ So that the preprocessor can convert those values to literal strings (EXPAND_AND_STRINGIFY), which can then be used as keys in the map as well as being the values in the enum.

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
You mean a single string literal. He has to use runtime code to split them into a list.

StickGuy
Dec 9, 2000

We are on an expedicion. Find the moon is our mission.
Are there any software packages out there that can analyze C/C++ floating point calculations to identify sensitive ones or suggest different orders of operations? Ideally something that could check based on the actual values used in the calculations.

Lexical Unit
Sep 16, 2003

beuges posted:

Why this:

...

instead of this:
code:
enum available_atom
{
	_NET_WM_STATE,
        _MOTIF_WM_HINTS,
        WM_NAME
};
What MarsMattel and Mustach said.

What I wanted is for the key to be the name of the Atom. But if the key was a string, then someone could typo and the program wouldn't work. I'd have to do runtime checking to make sure the key passed to get() was a valid key. And then what do I do if it isn't? Throw and exception probably.

So I made the enums be exactly what the key names should be, for clarity, and this will catch typos at compile time. Then I can use the same define, expand it and stringify it, and then parse it to get the string names that XInternAtoms() needs. In my real code I also use a std::map<available_atom, std::pair<Atom, std::string> > so that the user can get not only a reference to an Atom, but also the string name of an Atom if they so desire.

Senso
Nov 4, 2005

Always working
I've been working with Python, PHP and Perl for years now and I've recently decided to finally learn C++. I've started messing with SDL, just trying various things like moving a character on the screen and poo poo. I've been reading about SDL (and Allegro at the same time) because I want an easy graphics library. I know these two libs are old and not really taking advantage of current hardware and all that.

My question is, should I forget about SDL right now and switch to GTK? Is GTK really more complex than SDL? Or the other way around?

EDIT: VVVV So would you say that I'm wasting my time doing low-level stuff with SDL?

Senso fucked around with this message at 14:51 on Jul 30, 2008

Vanadium
Jan 8, 2005

Gtk is a GUI toolkit thing with buttons and menus and and dropdown boxes and poo poo, SDL is a 2D graphics thing where you just draw stuff on the screen on your own. They do not really have the same purpose.

Zombywuf
Mar 29, 2008

StickGuy posted:

Are there any software packages out there that can analyze C/C++ floating point calculations to identify sensitive ones or suggest different orders of operations? Ideally something that could check based on the actual values used in the calculations.

It's really hard to do this as the precision loss is data dependant. A very quick and dirty rule of thumb is: does your code add really small numbers to really big ones (multiplication is ok), if so you will lose precision - especially in a loop.

I've never heard of a tool to do this, and would be surprised to find one that worked. Your best bet might be an interpreter that you can run on realistic data that would check for lost precision. Or possibly (in C++):

code:
template<class FloatType, int Tolerance>
class precision_testing_float {
  FloatType _val;
public:
  ...
  precision_testing_float operator +(precision_testing_float rhs) const {
    if (abs(exponent(_val) - exponent(rhs._val)) > Tolerance) {
      cerr << "Warning: precision loss" << endl;
    }
    return precision_testing_float(_val + rhs._val);
  }
  ...
}

more falafel please
Feb 26, 2005

forums poster

Senso posted:

EDIT: VVVV So would you say that I'm wasting my time doing low-level stuff with SDL?

If you're trying to make a 2D game (or something else with graphics), no, SDL is a good idea. If you're trying to make a GUI with buttons and widgets and checkboxes, then SDL is a bad idea, GTK (or wxWidgets, or Qt) would be better. This is akin to asking if you should be using Direct3D or MFC.

Chin Strap
Nov 24, 2002

I failed my TFLC Toxx, but I no longer need a double chin strap :buddy:
Pillbug
Figure this is a good place to ask:

I'm used to doing most of my programming in things like R and Matlab, but I want to go to C++ in anticipation of project sizes that aren't going to work well in scripted languages. What are some good libraries out there for linear algebra and statistics?

Senso
Nov 4, 2005

Always working

more falafel please posted:

If you're trying to make a 2D game (or something else with graphics), no, SDL is a good idea. If you're trying to make a GUI with buttons and widgets and checkboxes, then SDL is a bad idea, GTK (or wxWidgets, or Qt) would be better. This is akin to asking if you should be using Direct3D or MFC.

OK I get it now. I don't have anything clear but I want to try my hands at a roguelike-style game, in ASCII. In that case, I'm wondering if using a GtkLayout or GtkDrawingArea to display a bunch of separate characters moving independently would work or if SDL (or say, ncurses for pure console mode) would be better for that.

Vanadium
Jan 8, 2005

Senso posted:

OK I get it now. I don't have anything clear but I want to try my hands at a roguelike-style game, in ASCII. In that case, I'm wondering if using a GtkLayout or GtkDrawingArea to display a bunch of separate characters moving independently would work or if SDL (or say, ncurses for pure console mode) would be better for that.

If you want to do the main game display "roguelike" and have a bunch of regular menus (like, say, an inventory list or whatever), you could probably well use Gtk for that. But if you want a fullblown roguelike, just go with ncurses.

Thug Bonnet
Sep 22, 2004

anime tits ftw

Is it possible to use the initialization list of an objects constructor to assign members of a struct (that's a member of the object)? This type of thing is giving me problems:

init_test.h
code:
struct test_struct{
	int struct_member;
};

class TestObject{
	struct test_struct ts;
	public:
		TestObject(int _struct_member);
};
init_test.cpp
code:
#include "init_test.h"

TestObject::TestObject(int _struct_member)::ts.struct_member(_struct_member);

chglcu
May 17, 2007

I'm so bored with the USA.

Thug Bonnet posted:

Is it possible to use the initialization list of an objects constructor to assign members of a struct (that's a member of the object)? This type of thing is giving me problems:

init_test.h
code:
struct test_struct{
	int struct_member;
};

class TestObject{
	struct test_struct ts;
	public:
		TestObject(int _struct_member);
};
init_test.cpp
code:
#include "init_test.h"

TestObject::TestObject(int _struct_member)::ts.struct_member(_struct_member);

I'm 99% sure you can't do that, but I've never tried it. What you can do is give your struct a constructor and call that in the initialization list:

code:
struct test_struct{
    int struct_member;
    test_struct(int _struct_member) : struct_member(_struct_member) {}
};

class TestObject{
    struct test_struct ts;
    public:
        TestObject(int _struct_member);
};

TestObject::TestObject(int _struct_member) : ts(_struct_member) {}

Adbot
ADBOT LOVES YOU

Thug Bonnet
Sep 22, 2004

anime tits ftw

prolecat posted:

I'm 99% sure you can't do that, but I've never tried it. What you can do is give your struct a constructor and call that in the initialization list:

code:
struct test_struct{
    int struct_member;
    test_struct(int _struct_member) : struct_member(_struct_member) {}
};

class TestObject{
    struct test_struct ts;
    public:
        TestObject(int _struct_member);
};

TestObject::TestObject(int _struct_member) : ts(_struct_member) {}

That is super clever, but it's not my struct :(

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply