C++11 is the latest iteration of the standard for the C++ programming language. This is the 2011 version of the standard that was known as C++0x in its draft form. (C++14 is forthcoming.) There were some new features of C++11 that I thought I’d play around with since I have a little bit of time between gigs. I'm a big believer in using C++ for embedded and even real-time applications whenever possible. But it's not a slam dunk. The language is complex, and growing more complex with every standards iteration.
Using C++ effectively has many benefits, even in the embedded/real-time domain. But it can place a burden on the development team; I have found it relatively easy to write C++ code that is nearly incomprehensible to anyone except the original author. Try debugging a complex problem in code that you did not write and that uses the Standard Template Library or the Boost Library to see what I mean.
My little test program that I've been futzing around with can be found here
http://www.diag.com/ftp/main.cpp
which is useful since Blogger seems to enjoy hosing up the angle brackets in my examples below that use templates.
I like the decltype but I wish they had used typeof to be consistent with sizeof. I cheated.
#define typeof decltype
long long int num1;
typedef typeof(num1) MyNumType;
MyNumType num2;
printf("sizeof(num1)=%zu sizeof(num2)=%zu\n", sizeof(num1), sizeof(num2));
class Thing {
private:
int x;
int y = 2;
public:
Thing(int xx) : x(xx) {}
Thing() : Thing(0) {}
operator int() { return x * y; }
};
Thing thing1, thing2(1);
printf("thing1=%d thing2=%d\n", (int)thing1, (int)thing2);
void * null1 = nullptr;
void * null2 = 0;
printf("null1=%p null2=%p equal=%d\n", null1, null2, null1 == null2);
struct Framistat {
char a;
alignas(int) char b;
char c;
};
printf("alignof(int)=%zu sizeof(Framistat)=%zu alignof(Framistat)=%zu\n", alignof(int), sizeof(Framistat), alignof(Framistat));
Framistat fram1[2];
printf("Framstat.a=%zd[%zu],b=%zd[%zu],c=%zd[%zu]\n"
, &fram1[1].a - &fram1[1].a, sizeof(fram1[1].a)
, &fram1[1].b - &fram1[1].a, sizeof(fram1[1].b)
, &fram1[1].c - &fram1[1].a, sizeof(fram1[1].c)
);
auto foo1 = 0;
auto bar1 = 'a';
printf("sizeof(foo1)=%zu sizeof(bar1)=%zu\n", sizeof(foo1), sizeof(bar1));
int foo3 { 0 };
char bar3 { 'a' };
printf("sizeof(foo3)=%zu sizeof(bar3)=%zu\n", sizeof(foo3), sizeof(bar3));
Here’s where my head explodes.
auto foo2 { 0 };
auto bar2 { 'a' };
printf("sizeof(foo2)=%zu sizeof(bar2)=%zu\n", sizeof(foo2), sizeof(bar2)); // WTF?
The sizeof(foo2) is 16. 16? 16? What type is foo2 inferred to be? I haven’t figured that one out yet.
I like the extended for statement where it can automatically iterate over a container or an initialization list. The statements
enum class Stuff : uint8_t {
THIS,
THAT,
OTHER,
};
for (const auto ii : { 1, 2, 4, 8, 16, 32 }) {
printf("ii=%d\n", ii);
}
printf("sizeof(Stuff)=%zu\n", sizeof(Stuff));
for (const Stuff ss : { Stuff::THIS, Stuff::THAT, Stuff::OTHER }) {
printf("ss=%d\n", ss);
}
std::list<int> mylist = { 1, 2, 3, 5, 7, 11, 13, 17 };
for (const auto ll : mylist) {
printf("ll=%d\n", ll);
}
const char * finder(std::list<std::pair
<int, std::string>> & list, const std::function <bool (std::pair<int, std::string>)>& selector){const char * result = nullptr;
if (selector(ll)) {
result = ll.second.c_str();
break;
}}
}
list.push_back(std::pair<int, std::string>(0, std::string("zero")));
list.push_back(std::pair<int, std::string>(1, std::string("one")));
list.push_back(std::pair<int, std::string>(2, std::string("two")));
list.push_back(std::pair<int, std::string>(3, std::string("three")));
for (auto ll : list) {
printf("ll[%d]=\"%s\"\n", ll.first, ll.second.c_str());
}
int selection;
selection = 0;
printf("list[%d]=\"%s\"\n", selection, finder(list, [&selection] (std::pair<int, std::string> entry) -> bool { return entry.first == selection; }));
selection = 1;
printf("list[%d]=\"%s\"\n", selection, finder(list, [&selection] (std::pair<int, std::string> entry) -> bool { return entry.first == selection; }));
selection = 2;
printf("list[%d]=\"%s\"\n", selection, finder(list, [&selection] (std::pair<int, std::string> entry) -> bool { return entry.first == selection; }));
selection = 3;
printf("list[%d]=\"%s\"\n", selection, finder(list, [&selection] (std::pair<int, std::string> entry) -> bool { return entry.first == selection; }));
selection = 4;
printf("list[%d]=\"%s\"\n", selection, finder(list, [&selection] (std::pair<int, std::string> entry) -> bool { return entry.first == selection; }));
Where C is a portable structured assembler language, C++ is a big, complicated, high-level programming language that can be used for applications programming or for systems programming. It has a lot more knobs to turn than C, and some of those knobs are best left alone unless you really know what you are doing. In my opinion it is much easier to write poor and/or incomprehensible code in C++ than it is in C. And this is coming from someone who has written hundreds of thousands of lines of production C and C++ code for products that have shipped, and who was mentored by colleagues at Bell Labs, which had a long history of using C++ in embedded and real-time applications. One of my old office mates at the Labs had worked directly with Bjarne Stroustrup; I sucked as much knowledge from his brain as I could.
C++, and especially C++11, is not for the faint hearted. But C++ is an immensely powerful language that can actually produce code that has a smaller resource footprint than the equivalent code in C... if such code could be written at all. C++ is worth considering even if you end up using a limited subset of it; although having said that, I find even widely used subsets like MISRA C++ too restrictive.
No comments:
Post a Comment