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
Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

That Turkey Story posted:

It's mostly due to the fact that prior to C++11 there was no way to create "variadic templates" (templates that can take any number of parameters).

The hilarious thing about MSVC is that there actually still isn't real variadic template support in VS2012 - they use 'faux variadics.' The following paragraph speaks for itself:

quote:

Faux variadics: We've developed a new scheme for simulating variadic templates. Previously in VC9 SP1 and VC10, we repeatedly included subheaders with macros defined differently each time, in order to stamp out overloads for 0, 1, 2, 3, etc. arguments. (For example, <memory> included the internal subheader <xxshared> repeatedly, in order to stamp out make_shared<T>(args, args, args).) In VC11, the subheaders are gone. Now we define variadic templates themselves as macros (with lots of backslash-continuations), then expand them with master macros. This internal implementation change has some user-visible effects. First, the code is more maintainable, easier to use (adding subheaders was a fair amount of work), and slightly less hideously unreadable. This is what allowed us to easily implement variadic emplacement, and should make it easier to squash bugs in the future. Second, it's harder to step into with the debugger (sorry!). Third, pair's pair(piecewise_construct_t, tuple<Args1...>, tuple<Args2...>) constructor had "interesting" effects. This requires N^2 overloads (if we support up to 10-tuples, that means 121 overloads, since empty tuples count here too). We initially observed that this (spamming out so many pair-tuple overloads, plus all of the emplacement overloads) consumed a massive amount of memory during compilation, so as a workaround we reduced infinity. In VC9 SP1 and VC10, infinity was 10 (i.e. "variadic" templates supported 0 to 10 arguments inclusive). In the VC11 Developer Preview, infinity is 5 by default. This got our compiler memory consumption back to what it was in VC10. If you need more arguments (e.g. you had code compiling with VC9 SP1 or VC10 that used 6-tuples), there's an escape hatch. You can define _VARIADIC_MAX project-wide between 5 and 10 inclusive (it defaults to 5). Increasing it will make the compiler consume more memory, and may require you to use the /Zm option to reserve more space for PCHes.

This story has a happy ending, though! Jonathan Caves, our compiler front-end lord, investigated this and found that something our tuple implementation was doing (specifically, lots of default template arguments), multiplied by pair's N^2 overloads, multiplied by how much pair tends to get used by STL programs (e.g. every map), was responsible for the increased memory consumption. He fixed that, and the fix is making its way over to our STL branch. At that point, we'll see if we can raise the _VARIADIC_MAX default to 10 again (as I would prefer not to break existing code unnecessarily).

Adbot
ADBOT LOVES YOU

raminasi
Jan 25, 2005

a last drink with no ice
Other "hilarious" things in MSVC include the fact that you can't capture a variable through nested lambdas unless you rename it, and using the auto keyword in C++/CLI code crashes the compiler.

tractor fanatic
Sep 9, 2005

Pillbug

GrumpyDoctor posted:

using the auto keyword in C++/CLI code crashes the compiler.

ahaha what?

hobbesmaster
Jan 28, 2008

GrumpyDoctor posted:

Other "hilarious" things in MSVC include the fact that you can't capture a variable through nested lambdas unless you rename it, and using the auto keyword in C++/CLI code crashes the compiler.

To be fair, everything in C++/CLI is broken.

tractor fanatic
Sep 9, 2005

Pillbug
And isn't WinRT supposed to use C++/CLI?

hobbesmaster
Jan 28, 2008

No, it uses C++/CX which is completely different from C++/CLI

Plorkyeran
Mar 22, 2007

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

hieronymus posted:

The hilarious thing about MSVC is that there actually still isn't real variadic template support in VS2012 - they use 'faux variadics.' The following paragraph speaks for itself:
The November CTP supports variadic templates, but it's been six months and the only update on when that'll make it into an actual release is a comment from Herb Sutter that they'll have something to announce by the end of June.

raminasi
Jan 25, 2005

a last drink with no ice

Looks like it might just be with static members of ref classes, but come on.

Zaphod42
Sep 13, 2012

If there's anything more important than my ego around, I want it caught and shot now.
Friend in college asked me to look at his code, had a bug he couldn't figure out.

All of the variables were named as single alphabet characters. :catstare:
Refused to look into it until he had proper variable names, and what do you know? Problem sorted itself out.

I guess that's just laziness? Ugh. How do you live with that? :commissar:

Victor
Jun 18, 2004

That Turkey Story posted:

It's mostly due to the fact that prior to C++11 there was no way to create "variadic templates" (templates that can take any number of parameters).
[...]
The issue is that the C and C++ preprocessor is extremely limited. You can't loop, you can't recurse, you can only do basic mathematical operations in certain contexts, etc. Basically, all that you can really do is concatenate tokens and use those concatenated tokens to result in the names of other macros that you can then expand. Remarkably, with this tiny bit of functionality, you can actually create containers and high-order algorithms, lambda functions, etc. but it requires the preprocessor code that's written to have redundancy. So in the end there is redundancy somewhere, but now the redundant code is generic and able to be used by any number of libraries that require variadic templates. It also, perhaps most importantly, is a library that is maintained by someone other than the person creating the library that needs variadic templates. It "just works." Now in C++11 we have direct support for variadic templates so you don't need to do the preprocessor stuff for them, although there are still other places where the preprocessor library is useful.

The point is, in the early 2000s the community was faced with a problem: either you just don't have things like tuple types and wait until the next standard (which came a decade later) or you manually maintain monstrous libraries that have considerable redundancy. The existence of the preprocessor library provided a third option -- have concise, maintainable libraries the remove the top-level redundancy by using the preprocessor.

Of course, this leaves you with people like myself, who would gladly use libraries like the tuple library back in the early 2000s because it's a tool that fits our needs, and people like Suspicious Dish (not meant as an insult) that do not want to use these libraries because of all of the hackiness going on behind the scenes -- What happens if something goes wrong? Do I want to have to trudge through preprocessor code? Is using the tool worth the other potential headaches?
Ahh, this makes more sense. Oddly enough, I was wondering about whether variadic templates were possible last night. Pre-C++11, I'd probably have made the decision based on how likely my dependence on them would result in horrible error messages. My experience with dealing with the CPP is that it's a PITA; are there ways of doing it that aren't obtuse? Even using C++ templates to do metaprogramming is obtuse; it's pretty hilarious to see my boss' ML code that explains what the templates are doing. Quite a bit more concise!

That Turkey Story
Mar 30, 2003

Victor posted:

Ahh, this makes more sense. Oddly enough, I was wondering about whether variadic templates were possible last night. Pre-C++11, I'd probably have made the decision based on how likely my dependence on them would result in horrible error messages. My experience with dealing with the CPP is that it's a PITA; are there ways of doing it that aren't obtuse? Even using C++ templates to do metaprogramming is obtuse; it's pretty hilarious to see my boss' ML code that explains what the templates are doing. Quite a bit more concise!

Unless the language completely changes, compile-time metaprogramming will always be a mess. Even features like constexpr do very little for anything but trivial metaprograming tasks.

shrughes
Oct 11, 2008

(call/cc call/cc)

Zaphod42 posted:

Friend in college asked me to look at his code, had a bug he couldn't figure out.

All of the variables were named as single alphabet characters. :catstare:

I had a friend in college who used pokemon names.

b0lt
Apr 29, 2005

shrughes posted:

I had a friend in college who used pokemon names.

I knew someone in college who programmed with a font that had the same glyph for 1, l, and I.

Victor
Jun 18, 2004

That Turkey Story posted:

Unless the language completely changes, compile-time metaprogramming will always be a mess. Even features like constexpr do very little for anything but trivial metaprograming tasks.
That's really unfortunate. One of the things my startup is trying to do is a C++ embedded library that compiles down to the same thing C would, but with the additional type safety and nicer syntax that C++ can give you.

zergstain
Dec 15, 2005

tractor fanatic posted:

Groups are in any abstract algebra class though, so you certainly don't need to go as far as category theory to encounter them.

I'm not taking abstract algebra in my degree though. I've seen everything that other guy mentioned, as well as poo poo like graphs, FSMs and recurrence relations. And I think a little bit on formal languages.

Dren
Jan 5, 2001

Pillbug

That Turkey Story posted:

Of course, this leaves you with people like myself, who would gladly use libraries like the tuple library back in the early 2000s because it's a tool that fits our needs, and people like Suspicious Dish (not meant as an insult) that do not want to use these libraries because of all of the hackiness going on behind the scenes -- What happens if something goes wrong? Do I want to have to trudge through preprocessor code? Is using the tool worth the other potential headaches?

There's a bit of a gray area in there between you and Suspicious Dish. I think it's fine to use metaprogramming stuff from a proven and maintained library like boost, although there are bits of boost I dislike. For instance, the other day I used tuple and boost::any to make a dispatch table. Boost's documentation is generally ok and so far I've been able to figure out any boost usage I've encountered.

The thing I don't like is when people go way down the template and preprocessor rabbit hole on their own and leave a giant, undocumented, impossible to maintain wart in the codebase. I recently ripped out what was undoubtably someone's baby -- a DSL for implementing an XML schema binding.

It was sort of a nightmarish jaxb. It was quite clever, it even included the ability to write an xsd for an object. Thing was, while the developer had made great strides to allow the representation of maps, vectors, and all the basic types, that was where the flexibility stopped. Want a map of vectors or a map of a map of something? Go into the lib and implement it yourself. Some bad decisions were being made regarding the design of the XML being used by this thing because the framework didn't support more complex data structures. There were other blotches too. It wrote all of its XML via boost serialization instead of with a real XML lib like Xerces. This occasionally caused problems. Worst of all, the DSL for specifying the data structure was completely undocumented, the developer is long departed and in house as well as third party devs were expected to figure it out with the aid of only a sparse example. You should see some of the crap code some third party interns working with this thing churned out.

Thank god it's gone. I've switched out the xml for json with the wjelement library. C++ json support is pretty woeful. Thankfully, wjelement is pretty kickin' rad. It even has json schema support and an xpath-like selector syntax. It's documentation has some holes but at least it has documentation.

C++ metaprogramming is not inherently bad, it's just really really easy for it to get messy and unmaintainable. If it's going to be done at all it should be done with the aid of boost since boost abstracts away most of the mess and provides docs. If you're doing it without boost then you better be unit testing and documenting it so hard because otherwise in the future it will confuse the piss out of some poor intern or re-purposed C programmer.

DarthRoblox
Nov 25, 2007
*rolls ankle* *gains 15lbs* *apologizes to TFLC* *rolls ankle*...
Here's a special present from one of our support engineers. (Lack of) indentation preserved:

select * from data_table where id_a in (
select id_a from table_a where id_b in (
select id_b from table_b where id_c in (
select id_c from table_c where relevant_field = criteria)) )
and (timestamp > sysdate - 12) and (timestamp < sysdate-6)

raminasi
Jan 25, 2005

a last drink with no ice
I think the example on this page counts as a documentation horror. Just leave it out, guys.

a nest of hornets
Nov 17, 2012

by Ralp

GrumpyDoctor posted:

I think the example on this page counts as a documentation horror. Just leave it out, guys.

Seeing http://www.contoso.com brought back a strange rush of nostalgia and hate

zergstain
Dec 15, 2005

After 4 months of being here (I'm on an 8 month co-op (that thing I said about only having 3 semesters left? I'm expecting to finish in April 2015)), I think I have something worthy of this thread.

code:

void
getnum(
        char *prompt,
        char *dflt,
        char *number,
        int bufsz,
        bool_t isssid)
{
...
        char *retval, answer[BUF_LEN];

        do {
...
                if ((retval == NULL) || (answer[0] == '\n') ||
                        (answer[0] == '\r')) {
                        if (dflt != NULL) {
                                (void) strlcpy(number, dflt, BUF_LEN);
                                return;
...
                ok = TRUE;
                for (i = 0; i < strlen(answer); i++) {
                        if (i >= (unsigned int)(bufsz - 1)) {
                                /* error message */
                                ok = FALSE:
                                break;
                        }
                        if (isssid) {
                                if ((string_to_lgui(answer, &ssid, &ptr) ==
                                    LGUI_NOTID) || (*ptr != '\0')) {
                                        /* error message */
                                        ok = FALSE;
                                        break;
                                }
                        } else {
...
        } while (ok != TRUE);

        (void) strlcpy(number, answer, BUF_LEN);
}

Some of that isn't verbatim, e.g. it actually prints error messages. It turns out that number is BUF_LEN in size every time this function is used, but using that instead of the size parameter when copying the result into the output buffer is BAD. Not to mention the stuff in the for loop that only needs to be done once.

I basically rewrote much of it, it's sitting in code review right now. I was told to put the original author on the review request because he needs to learn how to code better.

Dren
Jan 5, 2001

Pillbug
The code you posted is a horror but I'm not sure what it is supposed to do. I trust you removed the bits where it branches based on values in uninitialized memory?

zergstain
Dec 15, 2005

It's supposed to ask the user to enter a number. I left out
code:

                retval = fgets(answer, BUF_LEN, stdin);
I assume that's what you are talking about?

Dren
Jan 5, 2001

Pillbug

zergstain posted:

It's supposed to ask the user to enter a number. I left out
code:
                retval = fgets(answer, BUF_LEN, stdin);
I assume that's what you are talking about?

Yeah, it looked like the if clause was operating on retval and answer without them ever having been initialized.

zergstain
Dec 15, 2005

My main duty is fixing issues flagged in static analysis. It seems half the developers think you need to check for NULL before freeing, and often that's the only place they check, so the static analyzer goes :wtf: when the pointer is used because apparently the programmer thinks it could be NULL and forgot to handle it. Most of the time it will never be NULL because it errors out if malloc fails, or we use our xmalloc function which calls malloc in an infinite loop until malloc succeeds.

Most of the issues I fix aren't like that, but that one is pretty common. They also cast the free() argument to char *, what would make someone think this is necessary?

JawnV6
Jul 4, 2004

So hot ...

zergstain posted:

our xmalloc function which calls malloc in an infinite loop until malloc succeeds.

hey I found a horror

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
:staredog:

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
Even once I take my brain out of the "my kilobytes :negative:" mode, that's still insane. And also that is the opposite of what xmalloc is supposed to do!

quiggy
Aug 7, 2010

[in Russian] Oof.


How did anyone think that was a good idea.

zergstain
Dec 15, 2005

JawnV6 posted:

hey I found a horror

It sleeps the thread for 1 second. I don't know if you were thinking it just spins.

Scratch the part about it erroring out if malloc() fails, the analyzer would know that it couldn't get to the line that dereferences the pointer, so it wouldn't flag it.

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

zergstain posted:

They also cast the free() argument to char *, what would make someone think this is necessary?

I can answer this, C didn't always have void *. I guess if you learned C at Berkeley in the 70s you'd pick up that habit. On the other hand, K&R C didn't have typed arguments for functions either, so the cast is only relevant where pointers are a different size from int

VVVV Young whipper-snapper, what are these "argument types" you talk about? All functions take a variable number of int arguments, of course! :v: And malloc returns int, too, of course: stdlib.h? what's that?! just type "malloc", let the linker sort it out! (by the way, did you ever notice almost all C runtime function names are 6 characters or less...?)

hackbunny fucked around with this message at 18:52 on May 9, 2013

Rothon
Jan 4, 2012

zergstain posted:

Most of the issues I fix aren't like that, but that one is pretty common. They also cast the free() argument to char *, what would make someone think this is necessary?

I believe that in the pre ANSI-C days, void * wasn't a type so free took a char * which you'd need to manually cast to. It's the same reason that some people still do this cast
code:
struct foo *foos = (struct foos *) malloc(10 * sizeof(struct foo));

tractor fanatic
Sep 9, 2005

Pillbug
You also have to do that cast in C++

zergstain
Dec 15, 2005

hackbunny posted:

I can answer this, C didn't always have void *. I guess if you learned C at Berkeley in the 70s you'd pick up that habit. On the other hand, K&R C didn't have typed arguments for functions either, so the cast is only relevant where pointers are a different size from int

Yeah, I think most of the code like that was written in the mid 1990s, so maybe these guys graduated 20 years before that, and kept the habit.

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

hackbunny posted:

On the other hand, K&R C didn't have typed arguments for functions either, so the cast is only relevant where pointers are a different size from int

If I recall correctly, this is actually a characteristic of pre-K&R C, where all arguments were assumed to be word sized and no type checking had been done a la BCPL and B.

In K&R, you have typed arguments, but they're declared a little differently:
code:

void foo(a, b)
int a, char*b;
{
	/* do stuff */
}

fritz
Jul 26, 2003

Rothon posted:

I believe that in the pre ANSI-C days, void * wasn't a type so free took a char * which you'd need to manually cast to. It's the same reason that some people still do this cast
code:
struct foo *foos = (struct foos *) malloc(10 * sizeof(struct foo));

I do that, years of programming with compilers of varying age and quality have left me with all sorts of habits. (In actual practice tho I'd do
code:
int* data = (int*) calloc(10,sizeof(int))
instead of the malloc call because (a) I personally find the calloc easier to read than the malloc and (b) I almost always want to 0-fill the memory anyway.)

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av

Otto Skorzeny posted:

If I recall correctly, this is actually a characteristic of pre-K&R C, where all arguments were assumed to be word sized and no type checking had been done a la BCPL and B.

In K&R, you have typed arguments, but they're declared a little differently:
code:

void foo(a, b)
int a, char*b;
{
	/* do stuff */
}

They are typed and named in the definition. The declaration would simply be:
code:
foo(); /* what's "void", heathen? :V */
Nice and unambiguous :v:

E: this is still relevant in modern C due to variadic functions, and it leads to heaps of fun where sizeof(void *) != sizeof(int). You'd better hope nobody is passing 0 as a null pointer literal to a variadic function when you have to port to a 64-bit platform

hackbunny fucked around with this message at 19:07 on May 9, 2013

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe

zergstain posted:

It sleeps the thread for 1 second. I don't know if you were thinking it just spins.

This was not the correct answer.

nielsm
Jun 1, 2009



zergstain posted:

It sleeps the thread for 1 second. I don't know if you were thinking it just spins.

Okay one of your threads is spinning like that.
Now another thread needs to make an allocation. It starts spinning too.
A third thread, which happens to already be sitting on a significant amount of memory, needs a bit more. Guess what happens.
Now all of your threads are poking at the memory manager constantly, like little kids with their rooms bursting full of toys, begging their poor mom for more.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



It's OK - it only keeps going until someone notices the process isn't responding and kills it and they probably have a script for that.

Adbot
ADBOT LOVES YOU

nielsm
Jun 1, 2009



Munkeymon posted:

It's OK - it only keeps going until someone notices the process isn't responding and kills it and they probably have a script for that.

But you know, it'd be great if it could, like, just die all on its own if something like that happened, right?

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