Unfortunately, C++ constructors challenged the second one:
class SampleBuffer { public: SampleBuffer(int alen) ; SampleBuffer(char const * astring) ; protected: std::unique_ptrEither you lived with two copies of the initialization code, or you created a private init() function which you called from both constructors. Not ideal, but I never worked in a group large enough that I had to worry about someone trying to call init() other than in the constructor. Still, it could happen, and that would probably be bad.m_buffer ; int m_len ; } ; SampleBuffer::SampleBuffer(int alen) : m_len(alen) { * m_buffer = new char[alen +1] ; } SampleBuffer::SampleBuffer(char const * astring) { int tmplen= strlen( astring) ; * m_buffer = new char[tmplen +1 ]; m_len= tmplen ; strncpy( * m_buffer, astring, tmplen) ; }
In C++11 they added constructor chaining which have shown up in other languages like c sharp and java. So now the constructors can look like this:
SampleBuffer::SampleBuffer(int alen) : m_len(alen) { * m_buffer = new char[alen +1] ; } SampleBuffer::SampleBuffer(char const * astring) : DRYBuffer(strlen(astring)) { strncpy( * m_buffer, astring, m_len) ; }Already an improvement, especially if you decide to change something like having m_len represent the size of the buffer including the null terminator (heaven help you tracking down that off by one error in the original with the two separate code paths).
Obviously this is just an example (only a small step above the other trivial examples out there), but I've done the init() thing before for non-trivial cases, and this will be a handy alternative.
Of course there's the issue of where you can use this, and where you can't. It looks like g++ 4.6 does not support this, but g++ 4.7 on works fine.
Labels: c++, c++11, programming
These days I make a copy of the image, but originally I linked straight to the source, and now my 2004 pages are filled with broken pictures. I went back to fix a couple that seem to be popular still, one pointing to a favorite cartoon from Ink Tank. The artist took his original site down after a while, moved to a different domain, and has put some of the cartoons back online, but still has hundreds to go through.
Luckily I remembered another way to grab the original: The Internet Wayback machine. Yes, there's a site where they scoop up the whole internet and keep it in deep storage so you can see what hairdoos and trendy outfits looked like back in 1999. Ok, maybe we don't need that, but I was able to locate the original page for my Master Geek page, and restore the cartoon.
And here's another fun one restored at InkTank's new home: Board Chow.
Actually though, don't try this unless you want to skip lunch.
I had read way back when that there was a new standard with things added to the libraries like cross platform threads. I figured by now, I was behind the times, but I'd check it out and maybe update some of my libraries to work with the new standards way of doing things. According to the history page at The History of C++, the standard work was started in 2005 and was referred to as C++0x as it was expected to be done long before 2010. Hahaha. You can see the reference still in the command line options for GCC 4.6. But it took longer than expected, and the standard finally came out in 2011.
So now two years later, I 'm giving this stuff a test drive. Short answer? Its still sketchy.
My first test program should have been trivial, but I wanted each thread to have its own seeded random number generator. The page for rand() & rand_r() say that they're really not that good and you should use drand48, but I wasn't getting even basic cross platform support for drand48_r and somewhere the include files called it out as deprecated. Sigh.
On a wild guess, I went and took a look at the excellent documentation at cppreference, and while initially I did discover that the cpp library has a rand() function, its a mutex locked singleton. Also not what I wanted. But that at least got me to the random number generator section of the Numerics library, where with the help of some web resources, I figured out that I wanted to do:
typedef std::mt19937 rnd_type ;
std::uniform_int_distribution<rnd_type::result_type> urand(0, 400) ;
rnd_type m_rseed ;
m_rseed.seed( aseed) ;
int ival= urand( m_rseed) ;
auto rnd= std::bind(urand, m_rseed) ;
int ival= rnd() ;
std::chrono::microseconds us( 1) ;So what is missing from the pieces of this example? All the chrono stuff seemed to be there, it was the sleep_for call. On my six month old linux box, GCC 4.6 complained that "class std::thread has no member named sleep_for". Cygwin was up to GCC 4.7, and should have supported it, but the package maintainers didn't compile libstdc++ with the option --enable-libstdcxx-time, and so it was conditional'd out, and Visual Studio 2012 was not having any of it either.
m_thread->sleep_for( urand( m_rseed) * us) ;
Strangely enough, a later example with a slightly different variation:
std::this_thread::sleep_for( urand( m_rseed) * us) ;worked just fine, but I was still out on two out of three platforms. I switched back to nanosleep() on the linux platforms, but was not finding anything helpful on windows, so I finally threw in a Sleep(0) on windows. That gave me the strangest behavior ever. Unlike the *nix version where I would see a very close count of cycles between two threads which were sleeping random amounts between consuming a global counter; I was getting imbalances on Windows of 40% consistently (like 364 to 136). Turns out that Sleep(0) is nothing at all like Sleep(1) and is its own private hack. So I layered a dithering routine on top of Sleep like this:
int iadd ;and finally got reasonable results from the windows version.
iadd += urand( m_rseed) ;
if ( iadd > 1000 ) { Sleep( 1) ; iadd -= 1000 ; }
else { Sleep( 0) ; }
With great trepidation, I copied the example for conditional_variable wait_for() straight from here, and except for having to use my own platform specific sleep() routine again, it worked just fine except for one little detail in Visual Studio. The example used a macro for the atomic initializer:
std::atomic<int> i = ATOMIC_VAR_INIT(0);Visual Studio was having none of it, but changing it to simply i = 0 worked just fine.
The release notes for GCC 4.8 say they no longer require platform developers to specify the --enable-libstdcxx-time, so when that comes out in the next few months (?), we'll give it a try again. I have no idea what Visual Studio's plans are.
For now you can see my hacked up samples at github, along with other random test code.
Labels: c++, c++11, programming, threads
Feb '04
Oops I dropped by satellite.
New Jets create excitement in the air.
The audience is not listening.
Mar '04
Neat chemicals you don't want to mess with.
The Lack of Practise Effect
Apr '04
Scramjets take to the air
Doing dangerous things in the fire.
The Real Way to get a job
May '04
Checking out cool tools (with the kids)
A master geek (Ink Tank flashback)
How to play with your kids