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
wellwhoopdedooo
Nov 23, 2007

Pound Trooper!

Mustach posted:

:words:

The only thing in your list I have any real experience with other than make is SCons. And maybe I should say had experience, I used it from about 0.96 to 1.0. To be fair, that was a period of like two years.

Anyway, don't use it unless you know Python. Every SConstruct (Makefile) is a Python script, which is generally a good thing, but to get anything done other than exactly what they envisioned, you have to do some coding. The documentation was horrific, and somebody else mentioned performance for large projects. What they didn't mention is that it's even slow enough to be annoying on a tiny, 10-20 file project.

The thing that drove me to SCons was the same thing that seems to be driving you--dependency generation. I don't know how long GCC has had this, but it turns out, it can generate deps for you, and who would know better what the deps are than the compiler?

Here's the makefile for a screwing-around project I was working on. I won't claim it's any sort of "right", but it always got the dep tree right, and worst case it should point you to the right docs:

code:
CXXFLAGS = -pipe -O0 -fno-inline -frepo -fno-default-inline -g -ansi -Wall -Wextra -pedantic-errors -std=c++0x

GET_GCC_DEPS  = g++ -MM
GET_ONLY_DEPS = perl -pe 's/.*: |[^\\]\\\n//g'

MODULES = BodyTag \
          ContainerNode \
          HeadTag \
          HtmlTag \
          Node \
          NodeParser \
          PageNode \
          PTag \
          Tag \
          TextNode \
          TitleTag \
          DocTypeNode \
          test

OBJECTS = $(foreach MODULE,$(MODULES),$(MODULE).o)
RPOS    = $(foreach MODULE,$(MODULES),$(MODULE).rpo)

.SECONDEXPANSION:

all: test

clean-code: clean-inline_repositories clean-objects clean-programs

clean-docs:
        rm -rf doc

clean-inline_repositories:
        rm -f $(RPOS)

clean-objects:
        rm -f $(OBJECTS)

clean-programs:
        rm -f test

clean: clean-code clean-docs

$(OBJECTS): %.o: $$(shell $(GET_GCC_DEPS) %.cpp | $(GET_ONLY_DEPS))
        g++ $(CXXFLAGS) -c -o $@ $<

test: $(OBJECTS)
        g++ $(CXXFLAGS) -o $@ $^
The secondary expansion $$(shell ...) is key. The phony .SECONDEXPANSION rule is what enables it.

wellwhoopdedooo fucked around with this message at 14:34 on Apr 18, 2011

Adbot
ADBOT LOVES YOU

The Cheshire Cat
Jun 10, 2008

Fun Shoe

roomforthetuna posted:

And the rebuttal to his premise that C++ shouldn't be used for any new projects is to make a similar set of complaints about whatever language he suggests should be used instead. If there was a language that wasn't full of stupid flaws nearly everyone would be using it.

Counterpoint: nearly everyone uses C++ :v: (yes I realize this has nothing to do with it being any good and more to do with it being the language of choice for Microsoft, thus forcing anything Windows related to involve C++)

Anyway, serious question: Since the topic of pointers has come up recently, I'm a bit confused about the different usage in C++ compared to C. In C, if you want to pass by reference you would usually declare your function like void f(int *foo), and call the function like f(&someInt). Apparently in C++ though, you declare a function like void f(int &foo), and just call it like f(someInt)? Does this mean that in most cases I'll never actually need to use the * operator (aside from declaring a pointer variable)? This is assuming that pointer arithmetic is beyond the scope of what I need to do. Additionally, if the thing being passed by reference is an object, would I treat it inside the function as a pointer (so using -> to access members) or just a basic variable (thus using . insetad). I'm fairly new to C++ coming from a lot of experience with Java and C, so some of the syntactical quirks are really throwing me off.

Another basic question: Is there a standard for what goes in a particular .cpp file, like with Java's "One class per .java file"? I'm assuming it's just "use whatever everyone else on the team is using", where in my case the team is just me so it's "use whatever you feel works best", but if there is some kind of rule it would make it easier for me to figure out when I need to make a new file or when I can just include something in an existing file.

Theseus
Jan 15, 2008

All I know is if there is a God, he's laughin' his ass off.

The Cheshire Cat posted:

Another basic question: Is there a standard for what goes in a particular .cpp file, like with Java's "One class per .java file"? I'm assuming it's just "use whatever everyone else on the team is using", where in my case the team is just me so it's "use whatever you feel works best", but if there is some kind of rule it would make it easier for me to figure out when I need to make a new file or when I can just include something in an existing file.

There isn't really any kind of unified standard. I think the general rule most people follow is that a .cpp file should be a logical unit, namely that changes to it shouldn't require internal functionality changes in any other .cpp files. For example, in one of my current projects there's a .cpp file for an image streaming service and the classes that support it, and a second .cpp file for classes that handle encoding, etc.

Standish
May 21, 2001

The Cheshire Cat posted:

In C, if you want to pass by reference you would usually declare your function like void f(int *foo), and call the function like f(&someInt). Apparently in C++ though, you declare a function like void f(int &foo), and just call it like f(someInt)? Does this mean that in most cases I'll never actually need to use the * operator (aside from declaring a pointer variable)?
You still need pointers in C++:
  • for dealing with things that can be null
  • there's a fairly common coding convention to pass input-only parameters by (const) reference, input-output parameters by pointer (this is handy when reading code as you can tell from looking at a function call whether it modifies its parameters)
  • for using dynamic memory allocation
  • for calling C APIs, hurr

quote:

This is assuming that pointer arithmetic is beyond the scope of what I need to do. Additionally, if the thing being passed by reference is an object, would I treat it inside the function as a pointer (so using -> to access members) or just a basic variable (thus using . insetad). I'm fairly new to C++ coming from a lot of experience with Java and C, so some of the syntactical quirks are really throwing me off.
To access object fields via a reference, you use "." just like for objects.

Standish fucked around with this message at 18:14 on Apr 18, 2011

A MIRACLE
Sep 17, 2007

All right. It's Saturday night; I have no date, a two-liter bottle of Shasta and my all-Rush mix-tape... Let's rock.

Can someone who understands templates help me out? I'm working on an assignment that uses some of my professor's code, which is templated out. I'm trying to add a find function. Here is the code:
code:
template<typename Tkey, typename Twgt>
int cgraph<Tkey,Twgt>::find(string cname) {
    map<Tkey,int>::iterator it;
    size_t found;
    for (it=keymap.begin(); it!=keymap.end(); it++) {
        found = it->first.name.find(cname);
        if (found != string::npos) return it->second;
    }
    cout << "City containing " << cname << " not found!\n";
    exit(1);
}
and here are the messages I get when I try to compile:
code:
graph.h: In member function 'int cgraph<Tkey, Twgt>::find(std::string)':
graph.h:207: error: expected ';' before 'it'
graph.h:209: error: 'it' was not declared in this scope
graph.h: At global scope:
graph.h:217: error: 'template<class Tkey, class Twgt> struct cgraph' used without template parameters

Qwertycoatl
Dec 31, 2008

A MIRACLE posted:

Can someone who understands templates help me out? I'm working on an assignment that uses some of my professor's code, which is templated out. I'm trying to add a find function. Here is the code:
code:
template<typename Tkey, typename Twgt>
int cgraph<Tkey,Twgt>::find(string cname) {
    map<Tkey,int>::iterator it;
    size_t found;
    for (it=keymap.begin(); it!=keymap.end(); it++) {
        found = it->first.name.find(cname);
        if (found != string::npos) return it->second;
    }
    cout << "City containing " << cname << " not found!\n";
    exit(1);
}

C++ is dumb and doesn't know that "map<Tkey,int>::iterator" is the name of a type, rather than a member. If you change the second line to "typename map<Tkey,int>::iterator it;", it should work.

A MIRACLE
Sep 17, 2007

All right. It's Saturday night; I have no date, a two-liter bottle of Shasta and my all-Rush mix-tape... Let's rock.

Qwertycoatl posted:

C++ is dumb and doesn't know that "map<Tkey,int>::iterator" is the name of a type, rather than a member. If you change the second line to "typename map<Tkey,int>::iterator it;", it should work.

Thanks! I'm still getting
code:
error: 'template<class Tkey, class Twgt> struct cgraph' used without template parameters

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
The line of code that's happening on isn't in the chunk you posted.

The Cheshire Cat posted:

Anyway, serious question: Since the topic of pointers has come up recently, I'm a bit confused about the different usage in C++ compared to C. In C, if you want to pass by reference you would usually declare your function like void f(int *foo), and call the function like f(&someInt). Apparently in C++ though, you declare a function like void f(int &foo), and just call it like f(someInt)?
There isn't really a single agreed upon standard of when to use pointers and when to use references. My personal preference is to never use non-const references if I have a choice, as they make it much less obvious that a function mutates its arguments, but others like to use them whenever possible as it lets you encode in the typesystem that NULL isn't a valid value for that argument.

Plorkyeran fucked around with this message at 21:27 on Apr 18, 2011

HFX
Nov 29, 2004
Anyone recommend a good C\C++ logging framework similar to Log4J? I really like the ability to create module loggers, rolling logs, runtime configuration if I don't disable at compile time, etc. A Googling seemed to show ones that are either lacking, or have no active development.

Harokey
Jun 12, 2003

Memory is RAM! Oh dear!

HFX posted:

Anyone recommend a good C\C++ logging framework similar to Log4J? I really like the ability to create module loggers, rolling logs, runtime configuration if I don't disable at compile time, etc. A Googling seemed to show ones that are either lacking, or have no active development.

If you like Log4J why not use Log4cpp? http://log4cpp.sourceforge.net/

I haven't personally used it, but I've seen lots of other projects that use it.

Edit: of course, maybe this was one of the logging frameworks that did not have "active development"

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.

HFX posted:

Anyone recommend a good C\C++ logging framework similar to Log4J?
The only relatively full-featured one I could find was Boost.Log which isn't part of the Boost, but really wants to be. So the benefit is that it's quite flexible, the drawback is that the author is in love with templates and wants to marry them.

It's also a bit slow, but for our purposes that wasn't an issue.

HFX
Nov 29, 2004

Harokey posted:

If you like Log4J why not use Log4cpp? http://log4cpp.sourceforge.net/

I haven't personally used it, but I've seen lots of other projects that use it.

Edit: of course, maybe this was one of the logging frameworks that did not have "active development"

I looked at it. Not having been updated in 4 years worries me do to other dependencies in this project which haven't been updated in about as long and have caused major headaches.

BigRedDot
Mar 6, 2008

Sagacity posted:

The only relatively full-featured one I could find was Boost.Log which isn't part of the Boost, but really wants to be.
It was accepted, wasn't it? It hasn't gone in a release yet, but it will after some of its hand-rolled features get ported to some newer boost libs.

Paniolo
Oct 9, 2007

Heads will roll.

That Turkey Story posted:

Cross-posting this from the boost mailing list because I think it's pretty cool. I realized a new way to use enable_if in C++0x that offers a superset of the functionality that the current uses provide. If you ever wanted to use enable_if with overloaded conversion operations, now you can:

I'm glad I remembered you posting this, because I ran into a good use case for it today. Thanks!

Sagacity
May 2, 2003
Hopefully my epitaph will be funnier than my custom title.

BigRedDot posted:

It was accepted, wasn't it? It hasn't gone in a release yet, but it will after some of its hand-rolled features get ported to some newer boost libs.
Yes, that's true. The nice thing about that is that it will probably be maintained for the foreseeable future.

Joda
Apr 24, 2010

When I'm off, I just like to really let go and have fun, y'know?

Fun Shoe
My head doesn't work right. Nvm this post.

EDIT: I realised that while I was reading through my post. I changed the conditional to use iterGene1 and it works like it should now. My head has the worst timing. Thanks though. vvvvvv

Joda fucked around with this message at 18:21 on Apr 20, 2011

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
The conditional on the loop doesn't work, as iterGene2 skips past gene2.end().

PretendWizard
Sep 18, 2008
I'm running this

code:
cin>>response;

	switch(response){
		case 1:
			cout<<endl<<"Add a new Book"<<endl;

			cout<<endl<<"Please enter the Title: ";
			cin.getline(text1,50);

			cout<<endl<<"Please enter the Author: ";
			cin.getline(text2,50);
                ...
but it's skipping right to the input for Author. Whats the deal with that?

ed: VVVVVV Thanks

PretendWizard fucked around with this message at 20:07 on Apr 20, 2011

pseudorandom name
May 6, 2007

cin >> response reads an entire line of input, but only consumes the integer. The subsequent getline reads the remainder of that line of input.

A MIRACLE
Sep 17, 2007

All right. It's Saturday night; I have no date, a two-liter bottle of Shasta and my all-Rush mix-tape... Let's rock.

BRAINS! posted:

I'm running this

...

but it's skipping right to the input for Author. Whats the deal with that?

ed: VVVVVV Thanks

Look into using stringstreams for anything other than trivial input. Coming from C I had no idea what they were about but learned them and my code is a lot better for it.

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.
edit: ah, nevermind

emonkey
Jun 30, 2007

Plorkyeran posted:

The line of code that's happening on isn't in the chunk you posted.

There isn't really a single agreed upon standard of when to use pointers and when to use references. My personal preference is to never use non-const references if I have a choice, as they make it much less obvious that a function mutates its arguments, but others like to use them whenever possible as it lets you encode in the typesystem that NULL isn't a valid value for that argument.

My general opinion is that references were added to C++ to assist with operator overloading, and should only be used with types with overloaded operators. const references should be used 99.999% of the time unless you are defining operators.

the whole references being unable to be NULL is bunk anyway. This will still give you a runtime crash:

int *value = 0;
int &ref = *value;
ref = 1;

Since it can happen it does happen, especially if you ever have to call a function that takes a reference when all you have is a pointer.

UraniumAnchor
May 21, 2006

Not a walrus.

emonkey posted:

the whole references being unable to be NULL is bunk anyway. This will still give you a runtime crash:

int *value = 0;
int &ref = *value;
ref = 1;

Since it can happen it does happen, especially if you ever have to call a function that takes a reference when all you have is a pointer.

There are a million ways you can break things if you force it, but yes, you're right in that it's more of a coding convention than something enforced by the language.

Presumably if you have a situation like what you mention where you have a pointer that you need to cast to a reference, it'd be a good idea to check it for NULL first...

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.
Dereferencing a null pointer is undefined behavior. Everybody may implement references as pointers and turn that second assignment into a no-op, but that doesn't excuse omitting a null check when null is a possibility.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
Binding a reference to null is undefined behavior. Applying the dereference operator (*) to null is undefined behavior only if the subsequent lvalue is actually accessed, i.e. read, written from, or called (or bound to a reference, naturally).

ctz
Feb 6, 2003

rjmccall posted:

Applying the dereference operator (*) to null is undefined behavior only if the subsequent lvalue is actually accessed, i.e. read, written from, or called (or bound to a reference, naturally).

This is absolutely wrong with respect to C. I'm not sure about the exact semantics of C++ -- which puts me on par with the WG.

ctz fucked around with this message at 18:24 on Apr 21, 2011

shrughes
Oct 11, 2008

(call/cc call/cc)

Plorkyeran posted:

My personal preference is to never use non-const references if I have a choice, as they make it much less obvious that a function mutates its arguments, but others like to use them whenever possible as it lets you encode in the typesystem that NULL isn't a valid value for that argument.

Pointers already encode into the type system that NULL isn't a valid value for that argument (unless you explicitly document that the function accepts it).

wellwhoopdedooo
Nov 23, 2007

Pound Trooper!

shrughes posted:

Pointers already encode into the type system that NULL isn't a valid value for that argument (unless you explicitly document that the function accepts it).

I, too, like to make assumptions about what callers of my function will do, and enjoy the freedom to be wrong.

(p.s. in case it wasn't clear, no they loving don't)

(p.p.s. I mean jesus loving christ that is one of the most ignorant possible statements you could make concerning the C++ type system, and the explicit, exact opposite of what is actually true. If you had left out that the type system encodes this information your statement would have merely been stupid, if not stupid enough to comment on, but god drat it man I don't even ... this has got to be a troll, and I have been got. Good show.)

wellwhoopdedooo fucked around with this message at 01:40 on Apr 22, 2011

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.

rjmccall posted:

Binding a reference to null is undefined behavior. Applying the dereference operator (*) to null is undefined behavior only if the subsequent lvalue is actually accessed, i.e. read, written from, or called (or bound to a reference, naturally).
Interesting distinction. Do you know the rationale?

pseudorandom name
May 6, 2007

I don't know if you can call it a rationale, but it makes #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) possible.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

ctz posted:

This is absolutely wrong with respect to C.

Um, no, it isn't. It's just that anything you can do besides immediately applying & — including just ignoring the result — will either modify the l-value or cause an lvalue conversion, i.e. a load. C99 actually specifically says that &*x is a no-op.

ctz posted:

I'm not sure about the exact semantics of C++ -- which puts me on par with the WG.

I seem to remember this being somewhat clearer in an earlier draft, but now I can't find the wording, so maybe I dreamed it up.

shrughes
Oct 11, 2008

(call/cc call/cc)

wellwhoopdedooo posted:

I, too, like to make assumptions about what callers of my function will do, and enjoy the freedom to be wrong.

(p.s. in case it wasn't clear, no they loving don't)

(p.p.s. I mean jesus loving christ that is one of the most ignorant possible statements you could make concerning the C++ type system, and the explicit, exact opposite of what is actually true. If you had left out that the type system encodes this information your statement would have merely been stupid, if not stupid enough to comment on, but god drat it man I don't even ... this has got to be a troll, and I have been got. Good show.)

It's not a troll, it's a comment about how to read and write C++.

When you see a function that takes a pointer parameter and want to call it, the default assumption you should have is that the parameter cannot be null.

When you write a function that returns a pointer, it should never return null.

UraniumAnchor
May 21, 2006

Not a walrus.

shrughes posted:

When you write a function that returns a pointer, it should never return null.

So I guess all those functions that return NULL to signal some kind of error are poorly written?

I hope I'm just misunderstanding you.

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed

shrughes posted:

It's not a troll, it's a comment about how to read and write C++.

When you see a function that takes a pointer parameter and want to call it, the default assumption you should have is that the parameter cannot be null.

When you write a function that returns a pointer, it should never return null.
assuming things about what values are and aren't valid is sort of the opposite of encoding that information into the type system

wellwhoopdedooo
Nov 23, 2007

Pound Trooper!

shrughes posted:

It's not a troll, it's a comment about how to read and write C++.

When you see a function that takes a pointer parameter and want to call it, the default assumption you should have is that the parameter cannot be null.

When you write a function that returns a pointer, it should never return null.

You're making an arbitrary assumption. Your arbitrary assumption does not have the backing of the specification, but mine does, so you must either gain a benefit that my assumption does not, or not suffer from a problem that mine does, that is worth not having the backing of the specification.

In fact, you cannot even say I'm making an assumption--it's simply reality, a pointer can be any value that's valid for the datatype. Maybe I'm missing something. What's good about making your assumption that not making it doesn't give you?

wellwhoopdedooo fucked around with this message at 05:44 on Apr 22, 2011

That Turkey Story
Mar 30, 2003

shrughes posted:

It's not a troll, it's a comment about how to read and write C++.

When you see a function that takes a pointer parameter and want to call it, the default assumption you should have is that the parameter cannot be null.

When you write a function that returns a pointer, it should never return null.

Why would you ever assume this. This is the opposite of good practice and also is not implied by the type system.

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.

rjmccall posted:

I seem to remember this being somewhat clearer in an earlier draft, but now I can't find the wording, so maybe I dreamed it up.
You've shown your knowledge of the standards to be so high, that at this point, I think the text would just morph to fit your dream.

Claeaus
Mar 29, 2010
I'm having a problem with overloading operator=. Here's my code:
code:
const BST_Threaded& BST_Threaded::operator=(const BST_Threaded &T)
{
    if(&T == this)
        return *this;

    BST_Threaded *temp = new BST_Threaded(T);
    return *temp;
}
(BST_Threaded is my own class)
In my mind this will use the copy-constructor(that I have tested and know works), allocate memory for a new BST_Threaded and return it. But I just get an empty BST_Threaded.

I'm guessing it has something to do with how the memory is handled or something like that, so if someone could educate me on that it would be awesome!

litghost
May 26, 2004
Builder

Claeaus posted:

(BST_Threaded is my own class)
In my mind this will use the copy-constructor(that I have tested and know works), allocate memory for a new BST_Threaded and return it. But I just get an empty BST_Threaded.

I'm guessing it has something to do with how the memory is handled or something like that, so if someone could educate me on that it would be awesome!

operator= is not a copy-constructor, it is the assignment operator, for example:
code:
BST_Threaded a, b;

... use a and b for stuff

a = b;
Your code would get called, where this = &a, and T = b. You are supposed to modify "this" for whatever your equality operation is. The return is for chaining use (and should pretty much always be return *this). Chaining use would be something like:

code:
BST_Threaded a, b;

... use a and b for stuff

(a = b).start();

Adbot
ADBOT LOVES YOU

pr0metheus
Dec 5, 2010

That Turkey Story posted:

Why would you ever assume this. This is the opposite of good practice and also is not implied by the type system.

I think what shrughes means is that you are supposed to read documentation for a function and unless it says it will take or return a NULL you should assume that it should never happen. Otherwise its bad documentation.

That is pretty much the practice I have seen in most of of C libraries.

pr0metheus fucked around with this message at 14:42 on Apr 22, 2011

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