4

I've worked with C++ on some medium-sized project, but I have never did any serious programming in C.

Having read this article I've started wondering how I could use C++11 without classes and exceptions. I once heard the term clean C. Clean C supposed to be a C++ code which doesn't use C++ features that ANSI C doesn't have, like classes or metaprogramming.

There's plenty resources how to do things in C effectively and how to do them in C++. But it's surprisingly hard to find any resources on how to take the best of both worlds.

My question is two-part:

  1. Are there any good resources on using the C++ without namespaces, exceptions and metaprogramming? Books, open source projects?
  2. Please review this simple piece of code, which is my first attempt on handling data structures and char strings in mentioned subset of C++11. First thing comes to my mind is code redundancy. What woud you do differently and why?

-

#include <cstring>

namespace addressbook {
namespace contact {

struct contact {
    char* name;
    char* email;
};

void initialize(addressbook::contact::contact* contact)
{
    contact->name = nullptr;
    contact->email = nullptr;
}

void deinitialize(addressbook::contact::contact* contact)
{
    delete[] contact->name;
    delete[] contact->email;
}

void set_name(addressbook::contact::contact* contact, char* name)
{
    delete[] contact->name;
    contact->name = new char [strlen(name) + 1];
    std::strcpy(contact->name, name);
}

void set_email(addressbook::contact::contact* contact, char* email)
{
    delete[] contact->email;
    contact->email = new char [strlen(email) + 1];
    std::strcpy(contact->email, email);
}

} // namespace contact
} // namespace addressbook

int main()
{
    namespace c = addressbook::contact;

    c::contact jimmy;

    c::initialize(&jimmy);

    c::set_name(&jimmy, const_cast<char*>("Jimmy Page"));
    c::set_email(&jimmy, const_cast<char*>("jp@example.com"));

    c::deinitialize(&jimmy);

    return 0;
}

Please have mercy upon me - I'm a structural programming newbie.

Why not just C then?

Namespaces, new/delete, standard library algorithms, boost libraries, C++11 cool features - to name a few.

Why new/delete when you don't have constructors/destructors?

Because of type safety. malloc returns *void

But standard library throws exceptions! And boost does too!

The fact that I'm not using exceptions doesn't mean I can't handle exceptions coming from external libraries. It just means I want to manage problems differently in my part of the system.

  • 6
    Good question – but note that the article you link to is currently getting trounced in the C++ chat. – Konrad Rudolph May 10 '12 at 15:21
  • 5
    Why don't you just write C instead of C++ then? Also, if `set_email` doesn't modify the `email` parameter, it should be a `const char *` instead of a `char *`, that way you can get rid of those `const_cast`s – Praetorian May 10 '12 at 15:23
  • 3
    If you take all those features out, are you not left with just C? Why call it something other than C, if it is C? – R. Martinho Fernandes May 10 '12 at 15:24
  • One could say it's pretty obvious it's getting trounced in the C++ chat. :) –  May 10 '12 at 15:24
  • 2
    **Why not C then?** Namespaces, new/delete, constants, better typing control. –  May 10 '12 at 15:25
  • 1
    I remember pre -oo days. We spent most of our time inventing the mechanisms that underpin OO, or regretting that we didn't have time to do it. Aside from performance, very rare need, I've never heard a reasonable argument for not using OO. – Tony Hopkinson May 10 '12 at 15:25
  • 6
    What a silly thing to waste time on. I'm being forced to work in C here at work and while I used to be more open to the idea that C is just as good a language...it just isn't. C++ makes C obsolete. – Edward Strange May 10 '12 at 15:26
  • 2
    I would point out that...C++ without C++ features **is not** standard C! – Adriano Repetti May 10 '12 at 15:26
  • 1
    The question isn't a great fit with the FAQ and should be closed. – Nick May 10 '12 at 15:26
  • On the other hand, I did just waste my time writing boost bind in C macros :P Crazy hard, doesn't work half as well, requires calling a bunch of "DEF" macros outside of your functions, and requires you explicitly note type information...but it does do it. I'm also sitting on my thumbs a lot here. – Edward Strange May 10 '12 at 15:27
  • 1
    @Nick I disagree. This question fits the FAQ just fine. There is a concrete question and a quite definitive answer (though maybe not a unique one). It gets close to the “list of things” type of questions but in my opinion it’s still on the “good” side. – Konrad Rudolph May 10 '12 at 15:31
  • 6
    The author of that article is what is wrong with our field. – Edward Strange May 10 '12 at 15:34
  • 2
    What a silly nonsense, writing C++ without C++. It's almost like writing C# in C++... – Griwes May 10 '12 at 15:34
  • 7
    Voting to close. If you want C use C, not C++. While you can write C-compatible code and have it compiled with a C++ compiler (enhanced type checks), what you are asking makes no sense. The minute you ask for `new`/`delete` (or any other C++ feature) then you are giving up the C compatibility. So your question is basically: *How can I write C compatible code with C incompatible features?* – David Rodríguez - dribeas May 10 '12 at 15:39
  • I think he owns the site - he's only trying to get some attension ;-) – Bitmap May 10 '12 at 15:42
  • 1
    Can't argue about closing the question as not suitable for this site. But I still believe some of you guys miss my point. Some of you say that what I want is simply C and there's no reason to talk about C++ in my case whatsoever. That is not true. C has no namespaces, C has much poorer standard library, C has no boost, C has worse typing validation. C++11, even without classes and exception is not just C. –  May 10 '12 at 16:09
  • @Mikolaj: By your own definition of "clean C", you can't use namespaces in your clean C code. Or the C++ Standard library, or Boost, or anything like that. – Puppy May 10 '12 at 16:14
  • The standard library throws exceptions. – Edward Strange May 10 '12 at 16:15
  • @DeadMG, you're actually right. Probably some of the confusion is caused by my misdefinition of what I actually want –  May 10 '12 at 16:16
  • @CrazyEddie, see http://stackoverflow.com/questions/10537176/objects-without-classes-data-model-in-clean-c/10537292#comment13633218_10537292 –  May 10 '12 at 16:17

2 Answers2

11

But it's surprisingly hard to find any resources on how to take the best of both worlds.

Because there isn't one. The only reason to do such a thing is because you're desperate for compatibility- for example, Lua is written in "clean C". There's nothing "best" about it at all.

It's just C code pretending to be terrible C++ code. It's not C++ code but compatible. There's nothing better about "clean C" than regular C.

Edit: You, sir questioner, appear to have no idea WTF "clean C" even is. It's making your source code, even the implementations, C code that compiles as C++. No namespaces, no types, no constants, no nothing. C++-with-a-C-interface is a wholly different thing and totally unrelated to clean C. And in that case, there is no reason to limit which C++ features you use in the implementation.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 1
    As I commented under the question "Why not C then? Namespaces, new/delete, constants, better typing control." –  May 10 '12 at 15:26
  • 5
    "It's just C code pretending to be terrible C++ code." +1 – Griwes May 10 '12 at 15:27
  • 5
    @Mikolaj: None of those are present in clean C. There's a difference between offering a C interface, and making your source code C compatible. – Puppy May 10 '12 at 15:38
  • 2
    @DeadMG They are cited as reasons to use a cut-down C++ instead of C. I fundamentally still think it’s wrong to artificially limit C++ but this is still a very good rationale. – Konrad Rudolph May 10 '12 at 15:47
  • 1
    @Konrad: No, it isn't. If you're gonna sacrifice source compatibility with C, then why bother limiting yourself? And if you're gonna keep it, then you can't use any of them. – Puppy May 10 '12 at 16:10
  • @DeadMG For plenty of good reasons. Lack of support on you platform for one (embedded compiler …). Or dumb company guidelines. Whatever. The question was scoped. I agree with your caveat so there’s no use arguing about that. – Konrad Rudolph May 10 '12 at 16:14
  • @Konrad: There is a difference between "I simply cannot use exceptions in this code" and "I'm choosing not to use class constructors/destructors." The first is an obligate condition imposed by the compilation environment. The second is a *choice*. No C++ compilation environment would impose this; no compiler would dare call itself "C++" if it didn't implement *basic objects* correctly. And note that the OP is willing to use code that throws exceptions (Boost); he's simply choosing not to do so himself. – Nicol Bolas May 10 '12 at 17:41
  • @Nicol Read the post OP linked to. Again, I agree that the post is uninformed and draws the wrong conclusions but that doesn’t make the *question* and the reason employed therein invalid. – Konrad Rudolph May 10 '12 at 22:29
8

The first thing to note is that, even if we accept the article’s premises, there is no reason not to use classes. Maybe don’t use constructors, assignment etc. – But there’s no reason not to use member functions, for instance.

Next, don’t fall in the trap of using pointers all over the place. You should still prefer value semantics where possible. If you have to use pointers, use smart pointers instead of manual memory management, and note that even new can throw an exception (unless you use the std::nothrow overload).

And finally, don’t avoid C++ standard library functions in favour of C functions. For instance, don’t use strcpy – use std::copy and other C++ algorithms.


On a different note, a check for nullptr before delete[] is unnecessary.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Good, valuable points instead of "your question is just wrong or not really a question". Thanks! –  May 10 '12 at 15:34
  • 1
    @MikołajSiedlarek, I think that discouraging is highly recommended in this situation. – Griwes May 10 '12 at 15:37
  • @Griwes, Discouraging is fine really, but with some reasoning. –  May 10 '12 at 15:40
  • @MikołajSiedlarek, DeadMG reasoned IMHO very well; see that part I quoted under his answer. – Griwes May 10 '12 at 15:53
  • @Griwes, DeadMG reasoned that what I want is simply C and there's no reason to talk about C++ in my case whatsoever. That is not true. C has no namespaces, C has much poorer standard library, C has no boost, C has worse typing validation. C++11, even without classes and exception is not just C. –  May 10 '12 at 16:06
  • @MikołajSiedlarek, both Boost and Standard Library use the features you want to avoid. There are `throw`ing calls in stdlib and Boost. Both stdlib and Boost use classes. Sometimes even overuse them. What you are saying just doesn't make any sense. – Griwes May 10 '12 at 16:08
  • @Mikolaj: But that is NOT CLEAN C. – Puppy May 10 '12 at 16:10
  • 1
    @DeadMG Hence the quotes, and the *explicit definition* in the question’s text. Man, don’t get so hung up on names when an unambiguous description was provided. – Konrad Rudolph May 10 '12 at 16:13
  • 1
    @Konrad: Even his explicit definition clearly makes illegal all those features. "Clean C supposed to be a C++ code which doesn't use C++ features that ANSI C doesn't have". C does not possess namespaces, constants, C++ Standard library, Boost, anything like that. – Puppy May 10 '12 at 16:13
  • @Griwes, I don't believe that external libraries coding standards must influence my own code. Handling external exceptions is difficult and must be approached carefully no different if I'd use exceptions in my own code. –  May 10 '12 at 16:13
  • @MikołajSiedlarek, no, the features you are trying to avoid (and ultimately fail without them, to be honest) just have to be used properly, not avoided. EOT for me. – Griwes May 10 '12 at 16:16