Tuesday, September 1, 2015

Digest for comp.lang.c++@googlegroups.com - 25 updates in 8 topics

Christopher Pisz <nospam@notanaddress.com>: Sep 01 03:07PM -0500

I've created a new minimal compilable example of what I want to achieve
in production code. Can you guys take a look and see if I broke any
rules, created deadlock situations, did things right? I am new to
std::thread and std::condition_variable, not to mention C++11 vs C++98
in general.
 
One of my concerns in whether or not I should do anything in the
destructor of my ThreadedOnGoingTask and whether or not I've created any
potential deadlock by my use of std::condition_variable::wait_for with
shared variable g_stop.
 
Sorry, this code is long. Threading is complicated! This really is the
the most minimal compilable example I could come up with.
 
___
main.cpp
 
 
// Project Includes
#include "ThreadedOngoingTask.h"
 
// Shared Library
#include "Logger.h" // Replace with any threadsafe output
 
// Standard Library
#include <condition_variable>
#include <memory>
#include <mutex>
#include <thread>
#include <string>
#include <thread>
#include <vector>
 
#include <signal.h>
 
//--------------------------------------------------------------------------------------------------
// TODO - Only global for concept testing, later we'll wrap all this in
a class
std::vector<ThreadedOngoingTask::Shared_Ptr> g_workerObjects;
// Tasks wrapped in a class that represent each child thread
 
std::mutex g_threadsExitedMutex; // For
locks to read/write the following two variables
std::vector<std::shared_ptr<bool> > g_threadsExited; // Bool
that gets set to true by a child thread immediatly before the child exits
std::condition_variable g_threadsExitedCV; //
Condition Variable that gets notified immediatly before a child thread exits
 
std::mutex g_stopMutex; // For
locks to read/write the following two variables
bool g_stop; // Flag
stops child threads
std::condition_variable g_stopCV; //
Condition Variable that gets notified when child threads should exit
 
//--------------------------------------------------------------------------------------------------
void SignalHandler(int signal)
{
// Signal worker thread to exit
const std::string msg("Halt signal caught. Exiting all threads...");
Shared::Logger::getInstance()->logExecutionEvent(msg, __FILE__,
__LINE__, Shared::DateTime(),
Shared::Logger::LoggingLevel::LOG_LEVEL_DEBUG);
 
std::unique_lock<std::mutex> lock(g_stopMutex);
g_stop = true;
g_stopCV.notify_all();
}
 
//--------------------------------------------------------------------------------------------------
int main()
{
// Register a handler for the ctrl-z signal
signal(SIGINT, SignalHandler);
 
// Create the workers and start thier threads
for(size_t index = 0; index < 10; ++index)
{
std::shared_ptr<bool> threadExited(new bool(false));
 
ThreadedOngoingTask::Shared_Ptr worker(new
ThreadedOngoingTask(g_threadsExitedMutex,
threadExited,
g_threadsExitedCV,
g_stopMutex,
g_stop,
g_stopCV));
ThreadedOngoingTask::Start(*worker);
 
g_threadsExited.push_back(threadExited);
g_workerObjects.push_back(worker);
}
 
// Wait for all child threads to exit
std::unique_lock<std::mutex> lock(g_threadsExitedMutex);
while(std::any_of(g_threadsExited.begin(), g_threadsExited.end(),
[](std::shared_ptr<bool> threadExited){ return !(*threadExited); }))
{
g_threadsExitedCV.wait(lock);
}
 
// Clean up (even though these go away at exit..for debugging)
g_threadsExited.clear();
g_workerObjects.clear();
 
// Done
return 0;
}
 
____
ThreadedOngoingTask.h
 
#pragma once
 
// Standard Includes
#include <atomic>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <thread>
 
//--------------------------------------------------------------------------------------------------
class ThreadedOngoingTask
{
public:
 
typedef std::shared_ptr<ThreadedOngoingTask> Shared_Ptr;
 
static void Start(ThreadedOngoingTask & ThreadedOngoingTask);
 
ThreadedOngoingTask(std::mutex & threadsExitedMutex,
std::shared_ptr<bool> threadExited,
std::condition_variable & threadsExitedCV,
std::mutex & stopMutex,
bool & stop,
std::condition_variable & stopCV);
 
ThreadedOngoingTask(const ThreadedOngoingTask & rhs) = delete;
ThreadedOngoingTask & operator = (const ThreadedOngoingTask & rhs)
= delete;
~ThreadedOngoingTask();
 
protected:
 
void ThreadProcedure();
 
static size_t m_count;
size_t m_id;
std::thread m_thread; // Worker thread
this object will run on
std::function<void()> m_threadProcedure; // Function
object that is the main loop for the thread
 
std::mutex & m_threadsExitedMutex; // Owned by
parent thread. For locks to read/write the following two variables
std::shared_ptr<bool> m_threadExited; // Owned by
parent thread. Bool that gets set to true by a child thread immediatly
before the child exits
std::condition_variable & m_threadsExitedCV; // Owned by
parent thread. Condition Variable that gets notified immediatly before a
child thread exits
std::mutex & m_stopMutex; // Owned by
parent thread. For locks to read/write the following two variables
bool & m_stop; // Owned by
parent thread. Flag stops child threads
std::condition_variable & m_stopCV; // Condition
Variable that gets notified when child threads should exit
};
 
___
ThreadedOngoingTask.cpp
 
#include "ThreadedOngoingTask.h"
 
// Shared Includes
#include "Logger.h"
 
// Standard Includes
#include <iostream>
 
//--------------------------------------------------------------------------------------------------
size_t ThreadedOngoingTask::m_count = 0;
 
//--------------------------------------------------------------------------------------------------
void ThreadedOngoingTask::Start(ThreadedOngoingTask & ThreadedOngoingTask)
{
// Start the thread

ThreadedOngoingTask.m_thread.swap(std::thread(ThreadedOngoingTask.m_threadProcedure));
ThreadedOngoingTask.m_thread.detach();
}
 
//--------------------------------------------------------------------------------------------------
ThreadedOngoingTask::ThreadedOngoingTask(std::mutex & threadsExitedMutex,
std::shared_ptr<bool>
threadExited,
std::condition_variable &
threadsExitedCV,
std::mutex & stopMutex,
bool & stop,
std::condition_variable & stopCV)
:
m_id (m_count++),
m_thread (),
// Derived classes should override this behavior by binding their
own thread procedure in their constructor
m_threadProcedure
(std::bind(&ThreadedOngoingTask::ThreadProcedure, this)),
m_threadsExitedMutex(threadsExitedMutex),
m_threadExited (threadExited),
m_threadsExitedCV (threadsExitedCV),
m_stopMutex (stopMutex),
m_stop (stop),
m_stopCV (stopCV)
{
std::ostringstream msg;
msg << "ThreadedOngoingTask #" << m_id << " constructor has been
called.";
Shared::Logger::getInstance()->logExecutionEvent(msg.str(),
__FILE__, __LINE__, Shared::DateTime(),
Shared::Logger::LoggingLevel::LOG_LEVEL_DEBUG);
}
 
//--------------------------------------------------------------------------------------------------
ThreadedOngoingTask::~ThreadedOngoingTask()
{
std::ostringstream msg;
msg << "ThreadedOngoingTask #" << m_id << " deconstructor has been
called.";
Shared::Logger::getInstance()->logExecutionEvent(msg.str(),
__FILE__, __LINE__, Shared::DateTime(),
Shared::Logger::LoggingLevel::LOG_LEVEL_DEBUG);
 
// Note - std::thread has no mechanism of killing the thread
// I suppose we are in UDB here if the object is destroyed
before the thread exits
// I don't know what I should do. I don't really want to
flag all threads to exit by playing with the m_stop
// Do I just hope we never get here before it exited and
that all exceptions are caught in ThreadProcedure?
}
 
//--------------------------------------------------------------------------------------------------
void ThreadedOngoingTask::ThreadProcedure()
{
std::ostringstream msg;
msg << "ThreadedOngoingTask #" << m_id << " thread procedure has
been called.";
Shared::Logger::getInstance()->logExecutionEvent(msg.str(),
__FILE__, __LINE__, Shared::DateTime(),
Shared::Logger::LoggingLevel::LOG_LEVEL_DEBUG);
 
// Do not allow exceptions to escape the thread
try
{
// Loop forever until signalled to exit
std::unique_lock<std::mutex> lock(m_stopMutex);
 
while(!m_stopCV.wait_for(lock, std::chrono::seconds(10),
[this](){return m_stop;}) )
{
std::ostringstream msg;
msg << "ThreadedOngoingTask #" << m_id << " tick...";
Shared::Logger::getInstance()->logExecutionEvent(msg.str(),
__FILE__, __LINE__, Shared::DateTime(),
Shared::Logger::LoggingLevel::LOG_LEVEL_DEBUG);
}
}
catch(...)
{
std::ostringstream msg;
msg << "An unhandled exception occured in thread of
ThreadedOngoingTask #" << m_id << ". Stopping thread.";
Shared::Logger::getInstance()->logExecutionEvent(msg.str(),
__FILE__, __LINE__, Shared::DateTime(),
Shared::Logger::LoggingLevel::LOG_LEVEL_DEBUG);
}
 
msg.str("");
msg.clear();
msg << "ThreadedOngoingTask #" << m_id << " stopped. Exiting thread.";
Shared::Logger::getInstance()->logExecutionEvent(msg.str(),
__FILE__, __LINE__, Shared::DateTime(),
Shared::Logger::LoggingLevel::LOG_LEVEL_DEBUG);
 
// Notify parent the thread has exited
std::unique_lock<std::mutex> lock(m_threadsExitedMutex);
*m_threadExited = true;
std::notify_all_at_thread_exit(m_threadsExitedCV, std::move(lock));
}
 
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
mark <mark@invalid.invalid>: Sep 01 12:00PM +0200

In the paper 'Preventing Use-after-free with Dangling Pointers
Nullification', there is an example of Chromium using a pointer value
after delete:
 
[...]
delete doc->child;
allChilds[doc->child]=DELETED;
[...]
 
Is this undefined behavior?
 
Per C++11 standard:
 
3.7.4.2 Deallocation functions
<<<
If the argument given to a deallocation function in the standard library
is a pointer that is not the null pointer value (4.10), the deallocation
function shall deallocate the storage referenced by the pointer,
rendering invalid all pointers referring to any part of the deallocated
storage. The effect of using an invalid pointer value (including passing
it to a deallocation function) is undefined.
 
Does this imply that the example above has UB? This section is unclear
to me. The "clarification" "including passing it to a deallocation
function" doesn't help, since it implies a different kind of usage as
opposed to just using the pointer as numeric value.
Barry Schwarz <schwarzb@dqel.com>: Sep 01 05:34AM -0700

>after delete:
 
>[...]
>delete doc->child;
 
This implies that doc->child is a pointer (call it T*).
 
>allChilds[doc->child]=DELETED;
 
How can a pointer be used as the subscript of an array (or vector)? I
guess if allChilds were of type map<T*, int> and DELETED was an
expression compatible with int, this might make syntactic sense.
 
>[...]
 
>Is this undefined behavior?
 
Yes. Any attempt to evaluate a pointer after the memory it points to
has been deallocated is UB. It is not limited to dynamic allocation
either. Consider
int* foo()
{int i = 5;
return &i;}
int main()
{int *p;
int i;
p = foo();
i = *p; // UB-1
cout << p; //also UB-1
}
UB-1: You cannot dereference a pointer when you no longer own the
memory it used to point to.
UB-2: While not that common anymore, some hardware systems still
"validate" an address even if you are not accessing the memory at that
address.
 
>to me. The "clarification" "including passing it to a deallocation
>function" doesn't help, since it implies a different kind of usage as
>opposed to just using the pointer as numeric value.
 
I don't know why they added the parenthetical note. It adds nothing
to the sentence. It's like saying "Any attempt to perform arithmetic
(including addition) is ...". Any use of an invalid value is
undefined. Note that the pointer does not become invalid until the
function actually deallocates the storage. So
int *p = new int;
delete p; //OK
delete p; //UB
 
--
Remove del for email
Ralf Goertz <me@myprovider.invalid>: Sep 01 02:49PM +0200

Am Tue, 01 Sep 2015 05:34:33 -0700
 
> UB-2: While not that common anymore, some hardware systems still
> "validate" an address even if you are not accessing the memory at that
> address.
 
Really? I would have guessed there is no problem. Why should there be? A
pointer is nothing but a number. If this number is used as key in a map
why would any hardware try to validate the accessability of the memory
that happens to be situated at that address if not being asked to? If I
move to a new home and someone tries to look up my number in a phone
book the guy who moved into my previous home is not being bothered by
that. Only if that someone actually visits…
scott@slp53.sl.home (Scott Lurndal): Sep 01 01:26PM

>move to a new home and someone tries to look up my number in a phone
>book the guy who moved into my previous home is not being bothered by
>that. Only if that someone actually visits=E2=80=A6
 
A pointer is many things, depending on the hardware architecture.
 
It could be a linear address (intel x86 in long mode), it could
be a segment number/offset pair (intel x86 in segmented mode), it
could be an 8-digit signed BCD number (burroughs B4900) or it could
be a capability (burroughs B5500) or it could be an offset from
the stack pointer (HP-3000).
 
In the capability case, the pointer is an entry on the stack that
cannot be written to by the application and which describes the
bounds of the memory region accessible by the pointer. Been
around since the early 1960's and is still supported in Unisys
Clearpath systems.
"R. Schubert" <raphael.schubert@gmx.de>: Sep 01 06:44AM -0700

On Tuesday, September 1, 2015 at 12:00:34 PM UTC+2, mark wrote:
> to me. The "clarification" "including passing it to a deallocation
> function" doesn't help, since it implies a different kind of usage as
> opposed to just using the pointer as numeric value.
 
Working draft version N3797 is a bit more specific:
 
3.7.4.2
4. [...] Indirection through an invalid pointer value and passing an
invalid pointer value to a deallocation function have undefined behavior.
Any other use of an invalid pointer value has implementation-defined
behavior.[38]
 
[38] Some implementations might define that copying an invalid pointer
value causes a system-generated runtime fault.
 
It seems that, according to N3797:
- If operator[] does not dereference its argument and takes it by
reference, everything should be fine.
- If the argument is taken by value or copied internally, you may get an
error, depending on your system. But this behavior should be documented
and is therefore not undefined.
- If the argument is dereferenced (or passed to a deallocation function),
then you get UB.
 
From your version things are a bit muddier since I don't know your
standard's definition of "using". Instinctively I would have agreed with
Ralf's reasoning, but after reading the newer wording, I'm with Barry.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Sep 01 02:45PM +0100

On Tue, 1 Sep 2015 14:49:20 +0200
> asked to? If I move to a new home and someone tries to look up my
> number in a phone book the guy who moved into my previous home is not
> being bothered by that. Only if that someone actually visits…
 
§3.7.4.2/4 if C++11: "If the argument given to a deallocation function
in the standard library is a pointer that is not the null pointer
value, the deallocation function shall deallocate the storage
referenced by the pointer, rendering invalid all pointers referring to
any part of the deallocated storage. The effect of using an invalid
pointer value (including passing it to a deallocation function) is
undefined. [footnote: On some implementations, it causes a
system-generated runtime fault.]".
 
Copying a pointer which neither points to a valid object nor is null
can apparently cause a trap on some hardware. Although applying the
pointer value as the index of a map after deallocation would count as
"using" it (as would, say, incrementing or decrementing it), it should
be fine on x68/64, and probably on all other common architectures.
 
It is also invalid in C apparently.
 
Chris
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Sep 01 02:54PM +0100

On Tue, 1 Sep 2015 14:45:25 +0100
> "using" it (as would, say, incrementing or decrementing it), it should
> be fine on x68/64, and probably on all other common architectures.
 
> It is also invalid in C apparently.
 
Ahah, as pointed out by R Schubert, C++14 is more relaxed than C++11.
As opposed to C++98 and C++11, it makes copying a pointer an
implementation defined matter rather than being undefined.
 
§3.7.4.2/4 of C++14: "If the argument given to a deallocation function
in the standard library is a pointer that is not the null pointer
value, the deallocation function shall deallocate the storage
referenced by the pointer, rendering invalid all pointers referring to
any part of the deallocated storage. Indirection through an invalid
pointer value and passing an invalid pointer value to a deallocation
function have undefined behavior. Any other use of an invalid pointer
value has implementation-defined behavior. [footnote: Some
implementations might define that copying an invalid pointer value
causes a system-generated runtime fault.]"
 
Thanks to him for pointing that out.
 
Chris
legalize+jeeves@mail.xmission.com (Richard): Sep 01 07:11PM

[Please do not mail me a copy of your followup]
 
slp53@pacbell.net spake the secret code
>could be an 8-digit signed BCD number (burroughs B4900) or it could
>be a capability (burroughs B5500) or it could be an offset from
>the stack pointer (HP-3000).
 
How many people under the age of 30 have even *heard* of Burroughs?
 
I do like the examples, however :-).
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
scott@slp53.sl.home (Scott Lurndal): Sep 01 08:06PM

>>be a capability (burroughs B5500) or it could be an offset from
>>the stack pointer (HP-3000).
 
>How many people under the age of 30 have even *heard* of Burroughs?
 
The 'B' in BUNCH, none of which still remain in the
computer business.
 
https://en.wikipedia.org/wiki/BUNCH
 
Although the burroughs name has been revived for part of the
payment/check processing hardware/software that Burroughs/Unisys
used to sell.
Christopher Pisz <nospam@notanaddress.com>: Sep 01 02:05PM -0500

What kind of syntax do I use when trying to call
std::condition_variable::wait_for and I have a bool variable that I want
to use to control whether or not the predicate argument is true or false?
 
 
I currently have
 
while(m_stopCV.wait_for(lock, std::chrono::seconds(60),
std::move(m_stop)) == std::cv_status::timeout)
 
where
m_stopCV is a std::condition_variable &
lock is a local std::unique_lock
m_stop is a bool &
 
Also, I need m_stop to be protected by the mutex when it is evalutated.
How do I do that while using this function?
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
Christopher Pisz <nospam@notanaddress.com>: Sep 01 02:56PM -0500

On 9/1/2015 2:05 PM, Christopher Pisz wrote:
> m_stop is a bool &
 
> Also, I need m_stop to be protected by the mutex when it is evalutated.
> How do I do that while using this function?
 
I think I got it. Lamda Expression capturing this.
while(!m_stopCV.wait_for(lock, std::chrono::seconds(10), [this](){return
m_stop;}) )
 
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
scott@slp53.sl.home (Scott Lurndal): Sep 01 08:02PM


>I currently have
 
>while(m_stopCV.wait_for(lock, std::chrono::seconds(60),
>std::move(m_stop)) == std::cv_status::timeout)
 
 
The canonical way is:
 
pthread_mutex_lock(&lock);
while (!predicate) {
pthread_cond_wait(&cv, &lock); /* or pthread_cond_timedwait(); */
}
pthread_mutex_unlock(&lock);
 
std::condition_variable::wait_for() does all that
for you when the third (predicate) argument is a
function returning bool.
 
If you don't have a function returning bool, but rather
are accessing memory directly, then you need to worry about
volatile accesses to the predicate vis-a-vis compiler
optimizations.
Paul <pepstein5@gmail.com>: Sep 01 02:24AM -0700

I understand that, for many years (since about 03 perhaps), it's been fine to write
 
class SomeClass
{//
const static int x = 3;
//
};
 
More recently, (C++ 09 I think) we have been able to write
 
class SomeClass
{
//
int x = 3;
//
 
};
 
What I haven't been able to find out is what happens if the member variable is static and non-constant?
 
Can we write the below?
 
Thank you,
 
Paul
 
class SomeClass
{
//
static int x = 3;
//
 
};
legalize+jeeves@mail.xmission.com (Richard): Sep 01 07:08PM

[Please do not mail me a copy of your followup]
 
Paul <pepstein5@gmail.com> spake the secret code
 
>What I haven't been able to find out is what happens if the member
>variable is static and non-constant?
 
As I understand it, it is a shorthand for initializing non-static
members of a class.
 
>Can we write the below?
 
shell 179> g++ -std=c++0x /tmp/a.cpp
/tmp/a.cpp:7:17: error: ISO C++ forbids in-class initialization of
non-const static member 'SomeClass::x'
static int x = 3;
^
shell 180> cat /tmp/a.cpp
#include <cassert>
 
class SomeClass
{
public:
//
static int x = 3;
//
 
};
 
int main()
{
assert(SomeClass::x == 3);
SomeClass s;
assert(SomeClass::x == 3);
return 0;
}
 
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
Juha Nieminen <nospam@thanks.invalid>: Sep 01 08:17AM

> Should I abstain from asking questions here?
 
I think you should abstain from an attitude of the sort "I don't like this
language, therefore I'll make provocative passive-aggressive posts in the
newsgroup of that language, and get a hissy-fit when I get responded in
kind."
 
Do you at the very least agree that C is not a panacea, and that there
are tons and tons of C projects out there that are at least as much of
a mess as your C++ project?
 
Take any big open source C project out there, and there's at least 50%
chance that it will be absolutely horrible design-wise, will be horrendously
inefficient, will have at least one memory leak, and will most probably
not compile without warnings, or even errors.
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
jacobnavia <jacob@jacob.remcomp.fr>: Sep 01 12:17PM +0200

Le 01/09/2015 10:17, Juha Nieminen a écrit :
 
> Do you at the very least agree that C is not a panacea, and that there
> are tons and tons of C projects out there that are at least as much of
> a mess as your C++ project?
 
Of course I agree SIR!
 
(Otherwise I would be excluded from this group, sigh:-)
 
 
> chance that it will be absolutely horrible design-wise, will be horrendously
> inefficient, will have at least one memory leak, and will most probably
> not compile without warnings, or even errors.
 
YES SIR!
 
jacob :-)
 
P.S. You will agree however that debugging C code is orders of magnitude
easier than debugging templated C++ code... Well if you do not mind SIR!
Juha Nieminen <nospam@thanks.invalid>: Sep 01 11:18AM


> jacob :-)
 
> P.S. You will agree however that debugging C code is orders of magnitude
> easier than debugging templated C++ code... Well if you do not mind SIR!
 
Ok, you are now officially an asshole.
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
jacobnavia <jacob@jacob.remcomp.fr>: Sep 01 02:42PM +0200

Le 01/09/2015 13:18, Juha Nieminen a écrit :
> Ok, you are now officially an asshole.
 
This shows the education of Mr Nieminen and his attitude towards people
that do not have the same programming language tastes.
 
I do not call people names, Mr Nieminen, it is just bad taste.
 
 
jacob
Gareth Owen <gwowen@gmail.com>: Sep 01 03:59PM +0100

> language, therefore I'll make provocative passive-aggressive posts in the
> newsgroup of that language, and get a hissy-fit when I get responded in
> kind."
 
Heh.
 
Good luck with that.
legalize+jeeves@mail.xmission.com (Richard): Sep 01 07:05PM

[Please do not mail me a copy of your followup]
 
jacob@jacob.remcomp.fr spake the secret code
 
>In 2010, tokens and identifiers were resolved at template expansion
>time. Somehow this behaviour changed between 2010 and today and now I am
>getting hundreds of undefined references in those templates.
 
Please post one specific example of your problem. Change
identifiers/whatever if you feel you need to protect your source code.
 
Reproducing the problem in a small scope always helps me understand
the problem better. Sometimes, the problem isn't what I thought it
was at all.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
mark <mark@invalid.invalid>: Sep 01 03:28PM +0200

Another obscure language feature - defined in C++14 7.1.6.2/4.3.
 
Thankfully, gcc, clang and Visual C++ all issue warnings about returning
a reference to a local variable.
ram@zedat.fu-berlin.de (Stefan Ram): Sep 01 12:01PM

>template< class T, typename S >::std::unique_ptr< T >make_unique( S x )
>{ return( ::std::unique_ptr< T >(new T( my_forward< S >( x )))); }
 
And then, for two arguments:
 
template< class T, typename S, typename U >
::std::unique_ptr< T >make_unique( S x, U y )
{ return
( ::std::unique_ptr< T >
( new T( my_forward< S >( x ), my_forward< U >( y )))); }
 
(untested).
 
>template< typename T >T && my_forward( T && x )
>{ return static_cast< T&& >( x ); }.
 
Such a »my_forward« would only be needed to replace
»::std::forward« if one does not have »::std::forward«.
jt@toerring.de (Jens Thoms Toerring): Aug 31 11:41PM

> > mention, they can't be used as buffers the same way as vectors.
 
> Yes they can - by using slightly uglier syntax &string[0] (or (string.empty
> ()? NULL: &string[0]) instead of string.data().
 
I'll take your word for it;-)
 
Thank you and best regards, Jens
--
\ Jens Thoms Toerring ___ jt@toerring.de
\__________________________ http://toerring.de
Paavo Helde <myfirstname@osa.pri.ee>: Sep 01 12:32AM -0500

jt@toerring.de (Jens Thoms Toerring) wrote in
 
>> Yes they can - by using slightly uglier syntax &string[0] (or
>> (string.empty ()? NULL: &string[0]) instead of string.data().
 
> I'll take your word for it;-)
 
Thank you, but there is no need to take my word ;-) These are the
relevant quotes from the standard:
 
21.4.1 basic_string general requirements
 
5. The char-like objects in a basic_string object shall be stored
contiguously. That is, for any basic_string object s, the identity
&*(s.begin() + n) == &*s.begin() + n
shall hold for all values of n such that 0<= n < s.size().
 
21.4.5 basic_string element access
 
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
 
2. Returns: *(begin() + pos) if pos < size().
 
Cheers
Paavo
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: