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
floWenoL
Oct 23, 2002

User0015 posted:

If anyone was up for it, I had some questions I'd like to ask via e-mail. That, or start my own thread. I don't think a thread really warrants my questions, since they'd mostly be single question/comment types.

If only there were a thread specifically dedicated to (C++) questions not worth their own thread...

Adbot
ADBOT LOVES YOU

floWenoL
Oct 23, 2002

Painless posted:

Does anyone know what's going on with std::sort? Is it just that GCC 3.4.4 and visual c++ express suck at optimizing, or am I doing something wrong here?

You're comparing apples and oranges; your comparison function (which is wrong, by the way) is not the same as std::greater<int>.

I don't know if that's the only factor, but it's the most glaring one.

Contero
Mar 28, 2004

Avenging Dentist posted:

Real men use Boost.Spirit and write an EBNF grammar to parse the morse code. :smug:

This actually looks pretty awesome and I'd love to use it but I can't seem to find any really short examples of parsing something and actually doing anything with it aside from confirming that yes, a string does indeed fit an EBNF. Can you point me towards a simple example or write something that would parse and evaluate:

code:
AE = number
   | (AE + AE)
   | (AE - AE)
Since boost is so great and all :)

User0015
Nov 24, 2007

Please don't talk about your sexuality unless it serves the ~narrative~!

floWenoL posted:

If only there were a thread specifically dedicated to (C++) questions not worth their own thread...

To be blunt, part of the reason I'd prefer e-mail is to avoid responses like these.

Painless
Jan 9, 2005

Turn ons: frogs, small mammals, piles of compost
Turn offs: large birds, pitchforks
See you at the beach!

floWenoL posted:

You're comparing apples and oranges; your comparison function (which is wrong, by the way) is not the same as std::greater<int>.

I don't know if that's the only factor, but it's the most glaring one.

Oh heh, you're right. Fixing the comparison function makes qsort go about 2.5 times slower.

hexadecimal
Nov 23, 2008

by Fragmaster

User0015 posted:

If anyone was up for it, I had some questions I'd like to ask via e-mail. That, or start my own thread. I don't think a thread really warrants my questions, since they'd mostly be single question/comment types.

ok, feel free to email me at hexadecimal12f0af9@gmail.com

hexadecimal
Nov 23, 2008

by Fragmaster

Contero posted:

This actually looks pretty awesome and I'd love to use it but I can't seem to find any really short examples of parsing something and actually doing anything with it aside from confirming that yes, a string does indeed fit an EBNF. Can you point me towards a simple example or write something that would parse and evaluate:

code:
AE = number
   | (AE + AE)
   | (AE - AE)
Since boost is so great and all :)

I am also interested in this.

Avenging Dentist
Oct 1, 2005

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

floWenoL posted:

You're comparing apples and oranges; your comparison function (which is wrong, by the way) is not the same as std::greater<int>.

I don't know if that's the only factor, but it's the most glaring one.

Counting calls to rand in the performance test probably doesn't help either, since it obscures the actual amount of time spent sorting.

That said, I ran it on my machine and got the following in MSVC8 with O2:
qsort: 1.594s
std::sort: 1.313s

And on a Linux VM with GCC 4.3.2 and -O3:
qsort: 2.39s
std::sort: 0.89s

Oh, also: you need to include <functional> if you want to use std::greater.

Lexical Unit
Sep 16, 2003

Painless posted:

Using MinGW (-O3), the qsort part goes much (about three times) faster than the std::sort part, which is completely unintuitive. Ok, I thought, it might be doing some weird special processing for qsort, let's move the compare_desc function to a different file. Doing this made the qsort version go about two times slower, so obviously some special processing is going on. In Visual C++ express, the qsort version goes at about the same speed as in MinGW, but the std::sort version is about 1.5 times slower.
Does anyone know what's going on with std::sort? Is it just that GCC 3.4.4 and visual c++ express suck at optimizing, or am I doing something wrong here?

One thing to note is that on Windows clock() is wall time, but on Linux clock() is proc time. So your results may be a little funny because of that. I'm not 100% on what kind of time clock() on MinGW will return, but that's something to check.

FWIW compiling that program but replacing clock() with gettimeofday() on a *NIX system shows qsort() being half as fast as std::sort(). I don't have access to a Windows machine to test on though.

As for std::sort() acting differently on different compilers, the STL implementation you use is by default provided by your compiler. So depending on how well your compiler implements std::sort(), you may get varying performance. What you can expect, at least, is that if your STL implementation is standards conforming, that you'll have O(N log(N)) complexity.

Edit: Why hello there next page that I totally didn't see till I posted.

Lexical Unit fucked around with this message at 22:49 on Nov 24, 2008

Nahrix
Mar 17, 2004

Can't afford to eat out
Language: C

I'm trying to create an array of files, which gets filled in a separate function.

code:
FILE *file[10];

file[0] = NULL;

fillFiles(&file);

...

void fillFiles(FILE **file)
{
  ...

  for loop (i iterator)
  {
    *file[i] = fopen(blah);
  }

  ...
}
Compile-time warning:
warning: passing arg 1 of 'fillFiles' from incompatible pointer type

I know I'm either declaring file improperly in the first place, or setting the parameter in fillFiles improperly, but no combination of asterisks and/or brackets have come out successful so far. I would also like to understand what I'm doing wrong rather than just trying out different combinations in hopes of getting lucky.

Avenging Dentist
Oct 1, 2005

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

Contero posted:

This actually looks pretty awesome and I'd love to use it but I can't seem to find any really short examples of parsing something and actually doing anything with it aside from confirming that yes, a string does indeed fit an EBNF. Can you point me towards a simple example or write something that would parse and evaluate:

code:
AE = number
   | (AE + AE)
   | (AE - AE)
Since boost is so great and all :)

Here's the shortest example I can think of. Note that this isn't how you'd write a large parser in Spirit (the docs show more about that). Also note that Spirit is top-down and so left-recursion is not allowed.

http://paste.ifies.org/166

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Nahrix posted:

I know I'm either declaring file improperly in the first place, or setting the parameter in fillFiles improperly, but no combination of asterisks and/or brackets have come out successful so far. I would also like to understand what I'm doing wrong rather than just trying out different combinations in hopes of getting lucky.

file is an array of length 10 of FILE* (i.e. FILE*[10]). Therefore &file will be a pointer to an array of length 10 of FILE* (i.e. FILE*(*)[10]), which won't match the argument type, hence type failure. However, values of array type can "decay" automatically to values of pointer type; hence file can decay to a FILE**, which is exactly what you want.

Nahrix
Mar 17, 2004

Can't afford to eat out

rjmccall posted:

hence file can decay to a FILE**, which is exactly what you want.

But I'm using FILE** as a parameter already.

floWenoL
Oct 23, 2002

Nahrix posted:

But I'm using FILE** as a parameter already.

the expression "file" is of type FILE** (or decays to it) so adding &file is of type FILE***, and you're trying to pass it to a function which takes FILE**.

Avenging Dentist
Oct 1, 2005

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

Nahrix posted:

But I'm using FILE** as a parameter already.

He basically wrote a lot of words to say "call with file and not &file".

Adhemar
Jan 21, 2004

Kellner, da ist ein scheussliches Biest in meiner Suppe.

Avenging Dentist posted:

Besides that, your #define obscures compiler errors, behaves differently from the C++0x range-for standard, and uses post-increment on the iterator. :barf:

What's wrong with a post-increment on an iterator?

Painless
Jan 9, 2005

Turn ons: frogs, small mammals, piles of compost
Turn offs: large birds, pitchforks
See you at the beach!

Adhemar posted:

What's wrong with a post-increment on an iterator?

Post-increment copies the iterator, whether that was desired or not. If iterator copying is complex, there's a chance the compiler might not be able to optimize away the copying. Just in case, it's better to use pre-increment in all cases unless you need the copy.

floWenoL
Oct 23, 2002

Adhemar posted:

What's wrong with a post-increment on an iterator?

It creates a temporary needlessly, which may or may not be optimized out.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Adhemar posted:

What's wrong with a post-increment on an iterator?

A lovely compiler (or a decent compiler on a weird/complex iterator type) may create a useless copy if you use postincrement

e:floWenoL:argh:

Smackbilly
Jan 3, 2001
What kind of a name is Pizza Organ! anyway?
Is there any well-known pattern for this situation?

Say I have a bunch of classes all deriving from an abstract base. I have an object of type AbstractBase*, and I want to make a copy of it. How do I do this without RTTI and a big ugly switch statement?

The solution I came up with is for AbstractBase to have a pure virtual clone() method which each derived class implements as:

code:
AbstractBase* Derived::clone() const
{
  return new Derived(*this);
}
And then use that method to generate the copy.

Clearly it works, but it still seems somewhat inelegant to me since every time I derive a new class from AbstractBase I need to re-implement clone() to do exactly the same thing but with a new type.

What I'd really like is for AbstractBase to have basically a virtual copy constructor that would copy-construct the correct derived class when given a const Derived&. Obviously C++ does not support such a thing, but are there any well-known patterns for getting this behavior in an elegant way?

hexadecimal
Nov 23, 2008

by Fragmaster

Smackbilly posted:

Is there any well-known pattern for this situation?

Say I have a bunch of classes all deriving from an abstract base. I have an object of type AbstractBase*, and I want to make a copy of it. How do I do this without RTTI and a big ugly switch statement?

The solution I came up with is for AbstractBase to have a pure virtual clone() method which each derived class implements as:

code:
AbstractBase* Derived::clone() const
{
  return new Derived(*this);
}
And then use that method to generate the copy.

Clearly it works, but it still seems somewhat inelegant to me since every time I derive a new class from AbstractBase I need to re-implement clone() to do exactly the same thing but with a new type.

What I'd really like is for AbstractBase to have basically a virtual copy constructor that would copy-construct the correct derived class when given a const Derived&. Obviously C++ does not support such a thing, but are there any well-known patterns for getting this behavior in an elegant way?

i think you can override copy constructor. In your abstract class, there are probably some protected fields, so copy them in AbstractClass copy constructor then in the derived classes call the super constructor and copy the fields that are specific to derived class.

floWenoL
Oct 23, 2002

hexadecimal posted:

i think you can override copy constructor. In your abstract class, there are probably some protected fields, so copy them in AbstractClass copy constructor then in the derived classes call the super constructor and copy the fields that are specific to derived class.

This 'solution' is totally broken.

Smackbilly
Jan 3, 2001
What kind of a name is Pizza Organ! anyway?

hexadecimal posted:

i think you can override copy constructor. In your abstract class, there are probably some protected fields, so copy them in AbstractClass copy constructor then in the derived classes call the super constructor and copy the fields that are specific to derived class.

That's not the problem, though.

If I have a AbstractBase*, I can't know if the pointer is pointing to an object of type DerivedA or DerivedB or DerivedC, so I can't know which copy-constructor to call without using "RTTI and a big ugly switch".

Here's a concrete example:

code:
class AbstractBase
{
  public:
  virtual int foo() = 0;
};

class DerivedA : public AbstractBase
{
  public:
  virtual int foo() { return 1; };
};

class DerivedB : public AbstractBase
{
  public:
  virtual int foo() { return 2; };
};

AbstractBase* makeCopy(const AbstractBase* original)
{
   // Uh, what goes here?
}

int main()
{
  AbstractBase* p_base = new DerivedA();
  AbstractBase* p_copy = makeCopy(p_base);

  return 0;
}

Avenging Dentist
Oct 1, 2005

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

hexadecimal posted:

i think you can override copy constructor. In your abstract class, there are probably some protected fields, so copy them in AbstractClass copy constructor then in the derived classes call the super constructor and copy the fields that are specific to derived class.

Copy constructors, being constructors, are by definition non-virtual. That is, if i have a Base *foo = new Sub(); and I call Base(*foo) to copy it, Sub's copy constructor won't get called.

Off the top of my head, the easiest solution would be to use CRTP:

code:
class Base
{
public:
    virtual Base * clone() = 0;
};

template<typename SubT,typename BaseT>
class Cloner : public BaseT
{
public:
    virtual Base * clone()
    {
        return new SubT(static_cast<SubT &>(*this));
    }
};

class Sub : public Cloner<Sub,Base>
{
};
EDIT: whoops, I hosed up the CRTP inheritance. And mistyped a bunch of poo poo...

Avenging Dentist fucked around with this message at 03:10 on Nov 25, 2008

floWenoL
Oct 23, 2002

Avenging Dentist posted:

Off the top of my head, the easiest solution would be to use CRTP:

I'm pretty sure that won't work, given the earlier discussion about virtual functions from one superclass 'fulfilling' an abstract virtual function from another superclass.

I can't think of a way that avoids having to write clone() for each subclass. :eng99:

Edit:

Wait, what about

code:
class Base {
  virtual Base *clone() const = 0;
};

template <class T>
class BaseCloner<T> : public Base {
  virtual Base *clone() const { return new T(dynamic_cast<const T &>(*this)); }
};

class Sub1 : public BaseCloner<Sub1> {};

class Sub2 : public BaseCloner<Sub2> {};
You can even do:

code:
#define BASE_SUBCLASS(T) class T : public BaseCloner<T>

BASE_SUBCLASS(Sub1) {};

BASE_SUBCLASS(Sub2) {};
:nyoron:

floWenoL fucked around with this message at 03:15 on Nov 25, 2008

Avenging Dentist
Oct 1, 2005

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

floWenoL posted:

Edit:

Wait, what about

You mean... what I did but mistyped? :3:

Bitruder
Nov 29, 2003

Majoring in connect the dots and colouring
I am using g++ 4.3.2 on a 64-bit Linux Machine.

When I compile my code with -Wall I get the following two warnings:
code:
net.cpp:268: warning: statement has no effect
net.cpp:272: warning: statement has no effect
The thing is, these two statements clearly DO have effects:
code:
266         // Load Each Input
267         pElem = hRoot.FirstChild( "input" ).Element();
268         for( pElem; pElem; pElem = pElem->NextSiblingElement("input")) {
269             params.clear();
270             hInput = pElem;
271             pElemParam = hInput.FirstChild( "param" ).Element();
272             for ( pElemParam; pElemParam; pElemParam = pElemParam->NextSiblingElement( "param" )) {
273                if (pElemParam->FirstChild()->Type() == TiXmlNode::TEXT) {
274                     params[pElemParam->Attribute("name")] = pElemParam->FirstChild()->Value();
275                }
276             }
277             cout << "Amplitude: " << params["amplitude"] << endl;
278         }
I am using TinyXML and this code loops over children. When I run my program, I get "Amplitude: 1" so clearly the program reads the XML file, and enters the for loops even though the statements apparently have no effect.

Any ideas? Is this a bug in g++?

Vanadium
Jan 8, 2005

The warnings are refering to the first part of the for (;;) head. You are naming the variables, not declaring or assigning to them, and just naming them indeed has no effect.

Vanadium fucked around with this message at 14:31 on Nov 25, 2008

TSDK
Nov 24, 2003

I got a wooden uploading this one

Bitruder posted:

I am using g++ 4.3.2 on a 64-bit Linux Machine.

When I compile my code with -Wall I get the following two warnings:
code:
net.cpp:268: warning: statement has no effect
net.cpp:272: warning: statement has no effect
The thing is, these two statements clearly DO have effects:
code:
266         // Load Each Input
267         pElem = hRoot.FirstChild( "input" ).Element();
268         for( [b]pElem[/b]; pElem; pElem = pElem->NextSiblingElement("input")) {
269             params.clear();
270             hInput = pElem;
271             pElemParam = hInput.FirstChild( "param" ).Element();
272             for ( [b]pElemParam[/b]; pElemParam; pElemParam = pElemParam->NextSiblingElement( "param" )) {
273                if (pElemParam->FirstChild()->Type() == TiXmlNode::TEXT) {
274                     params[pElemParam->Attribute("name")] = pElemParam->FirstChild()->Value();
275                }
276             }
277             cout << "Amplitude: " << params["amplitude"] << endl;
278         }
I am using TinyXML and this code loops over children. When I run my program, I get "Amplitude: 1" so clearly the program reads the XML file, and enters the for loops even though the statements apparently have no effect.

Any ideas? Is this a bug in g++?
I've bolded the bits that are causing the warnings.

pElem and pElemParam are already declared, so those statements do nothing. You could either move the initialisation:
code:
267         for (pElem = hRoot.FirstChild( "input" ).Element();
268              pElem;
                 pElem = pElem->NextSiblingElement("input")) {
269             params.clear();
Or make it explicit you're not using that section of the statement:
code:
267         pElem = hRoot.FirstChild( "input" ).Element();
268         for( /***/; pElem; pElem = pElem->NextSiblingElement("input")) {
269             params.clear();
The /***/ above isn't needed, but is it good practice to draw attention to the fact that you're not using that section in the usual manner.

Presto
Nov 22, 2002

Keep calm and Harry on.

Nahrix posted:

code:
void fillFiles(FILE **file)
{
  ...

  for loop (i iterator)
  {
    [b]*file[i] = fopen(blah);[/b]
  }

  ...
}
Your second problem is that *file[i] would be a 'FILE' and fopen returns a 'FILE *'. You want to leave off the *.

Cosmopolitan
Apr 20, 2007

Rard sele this wai -->
How come you can't use a basic string in a conditional statement?

Like:
code:
string var, var2;

if (var = var2)
{
...
}
I think it has something to do with the operator ("=" vs "=="), but I'm not sure. Also, what's the difference between comparing two strings with an if statement, and using a cstring function, or stringVar.compare?

Smackbilly
Jan 3, 2001
What kind of a name is Pizza Organ! anyway?

floWenoL posted:

Wait, what about

code:
class Base {
  virtual Base *clone() const = 0;
};

template <class T>
class BaseCloner<T> : public Base {
  virtual Base *clone() const { return new T(dynamic_cast<const T &>(*this)); }
};

class Sub1 : public BaseCloner<Sub1> {};

class Sub2 : public BaseCloner<Sub2> {};

This worked great, thanks.

The only annoyance remaining is that I still have to explicitly check the pointer for NULL before I try to clone it, but I can't make C++ do everything for me, I guess. :)

Vanadium
Jan 8, 2005

Anunnaki posted:

How come you can't use a basic string in a conditional statement?

Like:
code:
string var, var2;

if (var = var2)
{
...
}

"=" is an assignment. The result of assigning a string to a string is a string, but the conditional statement wants something it can evaluate in a boolean context. You really just want to use "==" here.

quote:

Also, what's the difference between comparing two strings with an if statement, and using a cstring function, or stringVar.compare?

That question does not really make sense. You would use a cstring function or .compare along with an if-statement, not instead of it.

The cstring function (strcmp, I guess) is for "C strings", which are just pointers to characters, it does not work on std::strings, much like you cannot call .compare on a C string.

Cosmopolitan
Apr 20, 2007

Rard sele this wai -->

Vanadium posted:

That question does not really make sense. You would use a cstring function or .compare along with an if-statement, not instead of it.

The cstring function (strcmp, I guess) is for "C strings", which are just pointers to characters, it does not work on std::strings, much like you cannot call .compare on a C string.

I'm sorry, I meant doing what I did in the example code I posted (if (stringVar1 == stringVar2)), as opposed to .compare, or strcmp.

UraniumAnchor
May 21, 2006

Not a walrus.

Anunnaki posted:

How come you can't use a basic string in a conditional statement?

Like:
code:
string var, var2;

if (var = var2)
{
...
}
I think it has something to do with the operator ("=" vs "=="), but I'm not sure. Also, what's the difference between comparing two strings with an if statement, and using a cstring function, or stringVar.compare?

= is assignment, == is equality.

When you use a char array or a char pointer (C-style strings), == doesn't compare the underlying string, just whether or not they are stored in the same location, hence why you need strcmp().

std::string (C++-style strings) does what's called "overloading" of the == operator and actually calls a function in the string class that compares the underlying strings. So in the case above, you actually have it correct other than the = vs == mixup (which is a fairly common mistake and I know gcc at least will warn you in case you didn't mean to do that, there ARE times when you want to).

C and Java don't have overloading hence why they require a separate function to compare string values. Java DOES have a 'built-in' overload of string concatenation hence why 'name = "John" + " Smith"' works, but C does not, so you need strcat() there.

Vanadium
Jan 8, 2005

Oh, yeah, you want to use .compare over == if you only want to compare portions of the string.

Smackbilly
Jan 3, 2001
What kind of a name is Pizza Organ! anyway?

Anunnaki posted:

what's the difference between comparing two strings with an if statement, and using a cstring function, or stringVar.compare?

As Vanadium said, the functions in cstring are for C-style strings, which are really just raw arrays of characters terminated with a NUL ('\0') character. You really want to avoid using them in C++ code pretty much all the time. C++ has the string class, which is a full-fledge object with useful methods and constructors and overridden operators, etc.

If for some reason you really need a C-style string (for example, a system API that was written with C in mind), it is relatively easy to convert between C and C++-style strings: You can pass a C-string to the constructor of a C++ string to make a C++ string with the same value. You can use the C++ string object's assign() method to assign the value of a C-string to a C++ string. You can use the C++ string object's c_str() method to get a const pointer to a C-string with the same value as the C++ string.

So even if you have need to use C-strings in C++ code for compatibility reasons, always prefer storing the data as C++ strings and converting to and from C-strings only when necessary.

The main comparison functions in cstring are strcmp and strncmp. The latter is the same as the former except it has a max length parameter to account for the fact that a very common bug is for a C-string to lose its NUL byte, which causes the program not to know where the string ends and usually crash (this is the #1 reason not to use C-strings). strcmp/strncmp take two C-strings and returns a negative number, a positive number, or 0. Negative means that the first string is lexicographically before the second, positive means the opposite, and 0 means they are equal. Another caveat is that 0 is equivalent to false in the context of a conditional, so if(strcmp(a,b)) does exactly the opposite of what you might expect it to. Don't use strcmp.

With C++ strings, you can just use the normal <, <=, ==, !=, >=, > operators which all behave exactly as you would expect them to.

The compare() method in the string class is analogous to strcmp. It returns negative positive or zero with the same meanings as above (be aware again that 0 is false, so if(a.compare(b)) will evaluate to false if and only if they are equal!) The only reason you would usually want to use compare instead of the standard operators is because compare has some overloads that allow you to compare only certain parts of the strings, which could save you a call to substr in some cases.

Glasgerion
Jul 25, 2007
Strike on strike on
Resurrecting a question from before because I phrased it vaguely and still haven't gotten it right after messing around with it for hours. I'm trying to use the pdcurses library with mingw on windows vista. Can someone tell me how to set it up? I'm not real familiar with this sort of thing.

Cosmopolitan
Apr 20, 2007

Rard sele this wai -->

Smackbilly posted:

Very informative post.

:words:

I see, thanks for the post. And yeah, I read about C-string comparisons returning a 0 if they were equal, that kind of confused me (since 0 means false).

Adbot
ADBOT LOVES YOU

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Anunnaki posted:

I see, thanks for the post. And yeah, I read about C-string comparisons returning a 0 if they were equal, that kind of confused me (since 0 means false).

Yeah, often you'll see if(!strcmp(...)) used to test for equality of cstrings, sometimes this will be wrapped by an streq() macro or function

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