C++ Features Adapted as C Idioms

A lot of people on Holla Forums complain about C++ being too bloated and C being too lacking. Why not adapt C++ features as C programming practices?
For example: for constructor/destructor autocalls, void main(void) { thing_t my_thing; thing_construct(&my_thing); // ...do things... thing_destruct(&my_thing);} or the copy constructor, thing_t thing1, thing2;thing_construct(&thing1);thing_construct(&thing2);// ...thing_copy(&thing1, &thing2);// move constructorthing_move(&thing1, &thing2);//...void thing_move(thing_t *to, thing_t *from) { free(to->data); to->data = calloc(from->size, 1); memcpy(to->data, from->data, from->size); thing_destruct(from);}
It's not pretty, but I believe it's systematically similar. What does user think?

Other urls found in this thread:

github.com/crawl/crawl/blob/master/crawl-ref/source/ability.cc#L1796
dev.mysql.com/doc/refman/5.7/en/c-api-prepared-statements.html
dev.mysql.com/doc/refman/5.7/en/create-procedure.html
twitter.com/NSFWRedditImage

A lot of people on Holla Forums complain about C++ being too bloated and C being too lacking. Why not adapt C++ features as C programming practices?

Becuase if C programmers liked those features they wouldn't complain about them you idiot.

...

But that's what people already do in C and have been doing since before C++.

Why doing what you propose, instead of writing C-style code in C++ and using C++ features only when they are useful in the project, rather than spamming them everywhere?

It would still lack of garbage collection.

Nigger we avoid copying.

there is no reason not to use modern c++
its much better than c

It's worth not using modern C++ just to keep the modern C++ programmers out.

is parroting memes all you can do?

Because "bloat" is nothing but a meme.

It's true, though. And I'm a C++ programmer.

Strings in C are garbage.

You should read that book about doing oop with only ansi c

Y'all niggas gotta read the code to Dungeon Crawl Stone Soup. It's so fucking easy to follow that you'll realize you only ever need blame yourself when you end up with unreadable C

Stay bad.

struct arena_error : public runtime_error { explicit arena_error(const string &msg) : runtime_error(msg) {} explicit arena_error(const char *msg) : runtime_error(msg) {} };
C++ was a mistake.

OOP was a mistake.

This is some quality garbage, user. Thanks for the humor.
const char* card_name(card_type card){ switch (card) { case CARD_VELOCITY: return "Velocity"; case CARD_EXILE: return "Exile"; case CARD_ELIXIR: return "the Elixir"; case CARD_STAIRS: return "the Stairs"; case CARD_TOMB: return "the Tomb"; case CARD_WILD_MAGIC: return "Wild Magic"; case CARD_ELEMENTS: return "the Elements"; case CARD_SUMMON_DEMON: return "the Pentagram"; case CARD_SUMMON_WEAPON: return "the Dance"; case CARD_SUMMON_FLYING: return "Foxfire"; case CARD_RANGERS: return "the Rangers"; case CARD_SHAFT: return "the Shaft"; case CARD_VITRIOL: return "Vitriol"; case CARD_CLOUD: return "the Cloud"; case CARD_STORM: return "the Storm"; case CARD_PAIN: return "Pain"; case CARD_TORMENT: return "Torment"; case CARD_WRATH: return "Wrath"; case CARD_WRAITH: return "the Wraith"; case CARD_SWINE: return "the Swine"; case CARD_ORB: return "the Orb"; case CARD_ILLUSION: return "the Illusion"; case CARD_DEGEN: return "Degeneration"; case CARD_FAMINE: return "Famine";#if TAG_MAJOR_VERSION == 34 // Removed cards. case CARD_MERCENARY: return "the Mercenary"; case CARD_ALCHEMIST: return "the Alchemist"; case CARD_CURSE: return "the Curse"; case CARD_VENOM: return "Venom"; case CARD_FORTITUDE: return "Fortitude"; case CARD_HAMMER: return "the Hammer"; case CARD_XOM: return "Xom"; case CARD_FEAST: return "the Feast"; case CARD_WARPWRIGHT: return "Warpwright"; case CARD_SUMMON_UGLY: return "Repulsiveness"; case CARD_PLACID_MAGIC: return "Placid Magic"; case CARD_CRUSADE: return "the Crusade"; case CARD_HELM: return "the Helm"; case CARD_BLADE: return "the Blade"; case CARD_SHADOW: return "the Shadow"; case CARD_POTION: return "the Potion"; case CARD_FOCUS: return "Focus"; case CARD_HELIX: return "the Helix"; case CARD_DOWSING: return "Dowsing"; case CARD_BANSHEE: return "the Banshee"; case CARD_SOLITUDE: return "Solitude"; case CARD_PORTAL: return "the Portal"; case CARD_WARP: return "the Warp"; case CARD_BATTLELUST: return "Battlelust"; case CARD_METAMORPHOSIS: return "Metamorphosis"; case CARD_SHUFFLE: return "Shuffle"; case CARD_EXPERIENCE: return "Experience"; case CARD_SAGE: return "the Sage"; case CARD_TROWEL: return "the Trowel"; case CARD_MINEFIELD: return "the Minefield"; case CARD_GENIE: return "the Genie"; case CARD_GLASS: return "Vitrification"; case CARD_BARGAIN: return "the Bargain"; case CARD_SUMMON_ANIMAL: return "the Herd"; case CARD_SUMMON_SKELETON: return "the Bones"; case CARD_WATER: return "Water"; case CARD_SWAP: return "Swap";#endif case NUM_CARDS: return "a buggy card"; } return "a very buggy card";}

Let me guess, translations are done with pre-processor macros as well?

I didn't think it could actually be that bad.
> github.com/crawl/crawl/blob/master/crawl-ref/source/ability.cc#L1796

What's wrong with a big switch statement?
How would you be doing it?

I am working on a dataabase driven app write now, and goddamn, the number of mallocs required is stupid. String concatention in C is retarded.

Its as I'd that's already best practice.

and how do you do that? can you be more specific?
in any nontrivial program there will be some copying somewhere.

When not written by a Pajeet, code like this would compartmentalize rather than just glue fucking everything into a giant switch statement. A good way to realize what's wrong and also think about the right way to do it would be to ask yourself, "how would I add support for mods here?". You'd have some sort of struct representing things like this that would have its callback registered with the ability code. The result would be an ability.cc that is very small, ability code that could be grouped into its own file, and ability.cc could use datastructures to do the lookups rather than potentially roll through hundreds of comparisons looking for a match.

Maybe it's just your inexperience? C isn't Java, we avoid allocations. Software that has to be fast doesn't even use malloc.

I'm not sure how I can describe it, but it's really rare that good C and C++ copy anything. For an example, I just grepped 100k LoC of my C++ code for them and there were only 3.
There's probably a difference here depending on what language you came from. If you went from C to C++, you're unlikely to do something like add a copy constructor so you can let stl containers value copy your data because you know how fucking stupid what's going on under the hood is and know to avoid it.

Dennis Ritchie and Ken Thompson were the first Pajeets.

I don't think you understand how their implementation of abilities works. Your solution is more code, more files, and undoubtedly less efficient.


You keep using this joke as if it were the core design principle of UNIX. Tons of error recovery code is a waste of time, and bloat, unless you're writing a fault-tolerant financial system.

Because that defeats the purpose. The C++ people are saying that the language should do that for you. The C people argue that when the language does, unoptimized code is slow do to containing numerous operations that don't need to happen.

Take this code:
std::string makeString(){ return "Hello";}int main(){ std::string someString = makeString();}
A C person looks at this and says: makeString() is going to construct a temporary string object, allocating memory for and copying "Hello". Then, it is going to pass that to construct someString, which will allocate memory for and copy "Hello" again. That's 3 copies of "Hello" in memory.

A C++ programmer will note that the lowest optimization setting will return-value optimize away one of those copies, and one can modify someString without the program dying.


The C code is error prone, and expert C developers have shown time and again that they don't actually have the discipline to write correct C, let alone C-with-ad-hoc-classes.
The C++ code requires optimization to have suitable performance, and attracts Java programmers (the number of corporations that use Java means that there are a lot of shitty developers who know Java).


The only problem I've had with this is that you complex ownership rules. I let STL containers copy my data because then I know that the container owns the data. And then the Java-trained junior devs won't create memory leaks when they manipulate the container.

Use asprintf()

QNX and MINIX3 are resilient enough for emdedded use though.

Pass pointers.

Suppose you want to create a select /where SQL query from. From isolated strings. What do you do? Allocate a new string and copy everything into it. You could have a fixed size static buffer (fast), but then you aprori limit query length, and waste arbitrary space extending that limit. How long is the longest query?

C++ you can concatenate strings. (which probably just invokes its version of memory mangement to malloc anyway).

My droog. asprintf is implict malloc.

but C++ strings probably implicit malloc anyway, i didn't know about asprintf, and it cleans up my code

If you're sending SQL queries, malloc() is not going to be your bottleneck (the disk and/or network are), so you might as well just malloc every query string.

No, this is just bad. You have no excuse for this now that you have things like unique_ptr built in. Fix your code.

True. Abstraction has a cost.
Untrue. I'd be able to avoid that massive number of comparisons they're doing by having some form of map.

It sounds like you're trying to solve a problem incorrectly and that's the cause of your shitty code. You shouldn't be assembling SQL query strings dynamically. It's not 1999 anymore. Query strings should be static and prepared. Dynamic arguments to queries should be passed via positional APIs. Queries that need to change depending on the situation should be handled by stored procedures plus positional APIs. Proper SQL has almost nothing to do with query strings these days, they're only used at startup.

This. Views, functions and prepared statements are your friends, and stop making your code vulnerable to SQL injection.

You can either use prepared queries and bind values, or you can quote any SQL metacharacters. It doesn't matter which one you do, so long as you do it correctly. I often use both, depending on what's easier.
But that's just for sanitizing user input. Optimization might have different needs, but it's not a given that everything has to be optimized with prepared queries. I've worked on projects where low volume transactions were the norm, and the business logistics made high volume basically impossible anyway. Everything depends on the circumstances at hand.

It does matter. Passing dynamic query strings is inefficient as nothing can be cached, it's having to parse and replan queries all the time, and you're grinding user data through escaping which is both slow and extremely dangerous. Even good webdevs know not to do that so I can't call it webdev-tier.
That word even being in your vocabulary is a huge red flag. You mean 'escaping' in this context not 'sanitizing' but you've got a third world PHP Pro stink to you.

When your so abstracted away in your rails framework that you have no idea what the reality is.

Wtf. Ultimately, queries are dynamic. Why? Because we don't know apriori what to search the database for sc. If i knew apriori I was going to search the database for rows where firstname='example' . I wouldn't have a database. I would have a textfile with the values cached.

The second the query becomes dynamic (and useful) , you have string allocation issues in C. Why? Because libmysqlclient mysql_real_query takes a string argument. So ultimately, you, or some framework are going to malloc a string to go there, because C doesn't have string concatenation.

I wrote a wrapper function that is passed a hash and generates a syntactically valid SELECT/Where statement (thats sanitized) from pairs in the hash and a table name as an argument. But you still have to malloc the string.

If rails/nodejs whatever the fuck trend language your using now has a wrapper function to generate query strings from hashes (like I am dong anyway), know that its still allocating a new string, because ultimately, your using the C ABI on x86 which doesn't have string concatenation natively.

Your argument of just use rails is retarded.
Or I don't understand what your talking about

I don't know alot about C++ , but I just assembled this , and debugged with gdb, and it looks like main has a local variable someString ,which is passed as a pointer to makeString, which calls the C++ runtime to allocate a string at its address directly.

So, it seems this code doesn't 3 times. It copies "Hello" from .data to a string object once in allocating the string, directly where it belongs from makeString().

.file "test.cpp" .section .ctors,"aw",@progbits .align 8 .quad _GLOBAL__I__Z10makeStringv .LC0: .string "Hello" .globl _Unwind_Resume .text .align 2 .globl _Z10makeStringv .type _Z10makeStringv, @function_Z10makeStringv:.LFB1422: pushq %rbp.LCFI14: movq %rsp, %rbp.LCFI15: pushq %rbx.LCFI16: subq $40, %rsp #Create locals No Locals! Yikes.LCFI17: movq %rdi, -32(%rbp) #save RDI (argument, pointer to local in main) to local movq -32(%rbp), %rbx #move that same local to %rbx ?? leaq -9(%rbp), %rdi #load local variable address to %rdi (argument to new function) call _ZNSaIcEC1Ev@PLT leaq -9(%rbp), %rdx #Load address of another local into %rdx leaq .LC0(%rip), %rsi #load address of SOMETHING? into %rsi movq %rbx, %rdi #save old return value(address of someString local) of fn _ZNSaIcEC1Ev@PLT as %rdi (first argument).LEHB0: call _ZNSsC1EPKcRKSaIcE@PLT #This inits string object, now data is contain in string. #rbx now contains address of string.LEHE0: leaq -9(%rbp), %rdi call _ZNSaIcED1Ev@PLT #what is this? #no return value. takes argument local variable. jmp .L27.L30: movq %rax, -40(%rbp).L28: movq -40(%rbp), %rbx leaq -9(%rbp), %rdi call _ZNSaIcED1Ev@PLT movq %rbx, -40(%rbp) movq -40(%rbp), %rdi.LEHB1: call [email protected]:.L27: movq -32(%rbp), %rax addq $40, %rsp popq %rbx leave ret.main:.LFB1423: pushq %rbp.LCFI18: movq %rsp, %rbp.LCFI19: pushq %rbx.LCFI20: subq $40, %rsp #create local variables. only local variable is someString!! yikes. 40.LCFI21: leaq -16(%rbp), %rdi #load the address of local variable into RDI (argument to makestring).LEHB2: call _Z10makeStringv #call makestring.LEHE2: leaq -16(%rbp), %rsi #load address of that local variable into rsi movq _ZSt4cout@GOTPCREL(%rip), %rdi #some kind of local variable gaurd argument.LEHB3: call _ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E@PLT //call.LEHE3: movl $0, %ebx leaq -16(%rbp), %rdi #load address of local variable into rdi.LEHB4: call [email protected]: movl %ebx, -28(%rbp) jmp .L31.L34: movq %rax, -40(%rbp).L32: movq -40(%rbp), %rbx leaq -16(%rbp), %rdi call _ZNSsD1Ev@PLT movq %rbx, -40(%rbp) movq -40(%rbp), %rdi.LEHB5: call [email protected]:.L31: movl -28(%rbp), %eax addq $40, %rsp popq %rbx leave ret

Did you even read my post you triple-decker nigger? I explained you don't always have to care about optimizing that stuff, and especially it matters jack all when the disk or network I/O is the bottleneck.
And any decent library has a convenient way to escape metacharacters, you don't have to do it by hand like a monkey. And if you weren't a monkey, you'd know that.

It's the destructor for std::allocator, apparently.

Also, looks like you forgot to add -O3 :^)

You really need to learn how to use a database properly before writing a library for one as your head is full of rocks. Again, like I said, you don't use query strings anymore past startup. You use prepared statements of static strings:
dev.mysql.com/doc/refman/5.7/en/c-api-prepared-statements.html
And when queries do need to be more dynamic than the number of parameters you use prepared statements to stored procedures:
dev.mysql.com/doc/refman/5.7/en/create-procedure.html
It's a totally different protocol under the hood when you do this. Instead, you're forcing the thing to use a compatibility API from the '90s. Even the mistake that is MySQL has a C API like this but you should really be using PostgreSQL. But, baby steps.
I don't even know rails, I'm a C programmer. Get your head on straight, user.

No, you made an attempt to justify unsafe Pajeetcode. This was you:
Disgraceful. A shameful display. Apologize to your father for disappointing him.

Am idiot. Can confirm. Thanks for that. Wish I started with this API. First on the documentation is mysql_real_query . Fuck.

Writing it this retarded way was still insightful. I am glad mysql exposes another API.