Friday, July 24, 2015

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

red floyd <no.spam.here@its.invalid>: Jul 21 08:19AM -0700

On 7/20/2015 11:59 AM, Richard wrote:
 
> A tautology is a thing that is tautological.
 
https://xkcd.com/703/
Martijn van Buul <pino@dohd.org>: Jul 21 09:28AM

* fl:
> about programming for embedded RTOS system, although the code may be for the
> test bench (less embedded in some sense). I code a lot at the lower level. It
> is the first time I know valgrind+callgrind.
 
Programming for an RTOS requires a different mindset every now and then,
depending on the real-time restrictions and the platform. For example,
the *maximum* runtime requirements of an algorithm is often more important
than the *average* requirement, because the first is a limiting factor on
response time. Available memory and processor resources often don't scale as
easily, and some C++ features (or parts of the standard library) just don't
combine well with a hard real-time behaviour.
 
Often, the mere fact that you use an RTOS has implications beyond the
obvious. On modern desktop and server operating systems, a stack overflow
is almost unheard of, but on RTOS systems, stack space is usually *very*
limited, so you need to be aware of deeply recursive routines, or large objects
placed on the stack. Deadlocks are often more fatal; if your browser stalls for
a couple of seconds it is annoying; if the ECU of a car stalls it can lead to a
deadly accident.
 
Granted, this is all about "how to write your algorithm" and "what pitfalls
to avoid" rather than "what tricks to use to get a perceived boost", and
personally, I don't think "speed improvement" covers anything of the required
skills to sucessfully handle real-time programming.
 
--
Martijn van Buul - pino@dohd.org
legalize+jeeves@mail.xmission.com (Richard): Jul 20 10:52PM

[Please do not mail me a copy of your followup]
 
Paul <pepstein5@gmail.com> spake the secret code
 
>Suppose, for example, that I'm designing a tree where the number of
>nodes descending from any particular node is variable. Any reason not
>to put nodes in vectors of std::unique_ptr<T>
 
Use shared_ptr<> and unique_ptr<> to indicate ownership lifetimes.
 
There's no reason to stop using local variables (including parameters)
that are raw pointers when it is clear that this does not imply a
transfer of ownership.
 
Usually, but not always, a container of items allocated on the heap
manages the lifetime of those items. If those items are shared, then
it's a container of shared_ptrs, if those items are uniquely owned by
the container, then it's a container of unique_ptr.
 
There are times when a container does not manage the lifetime of the
pointers inside it (temporary data structures built up during
processing are a good example) and in these cases, it could be
disastrous to have a container of smart pointers because the container
doesn't own the resources pointed to by the raw pointers.
--
"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>
Ian Collins <ian-news@hotmail.com>: Jul 16 09:49AM +1200

Richard wrote:
> side benefit of creating the insulting domain specific layer. You end
> up with interfaces that more directly describe the specific services
> needed by your application.
 
A lot of the code I write (and have to test) falls into that category,
hence the need to mock the system calls!
 
--
Ian Collins
legalize+jeeves@mail.xmission.com (Richard): Jul 16 03:53PM

[Please do not mail me a copy of your followup]
 
Ian Collins <ian-news@hotmail.com> spake the secret code
>> from Win32 then you'll want something more automated.
 
>A lot of the code I write (and have to test) falls into that category,
>hence the need to mock the system calls!
 
Yeah, I can see that if you're writing lots of system oriented code.
However, lots of C APIs are really thinly disguised objects. They have
some C function you call to obtain a resource and another function you
call to release a resource. So a wrapper can still be useful in these
circumstances to map the C api to a more object-oriented api that
ensures that resources are always properly released. Still, for unit
testing that stuff you need to mock out the underlying system API
calls. I've done it via both static and dynamic polymorphism to allow
me to decouple myself from the specific API call. It's more tedious
to do link-time substitution when the things you're mocking are in
Windows DLLs. I haven't tried link-time mocking Windows DLLs myself
but a coworker who tried it said that it was really quite painful. I
didn't review the code he did, so I don't know exactly what the pain
was, but I can imagine that link-time mocking without some sort of
tool that automates the process could be quite tedious.
--
"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>
Ralf Goertz <me@myprovider.invalid>: Jul 16 10:39AM +0200

Hi,
 
is it possible to have the new auto syntax for loops and get an iterator
instead of a copy or a reference to the stored object itself? I would
love to use the new syntax, but often I need to know what number in a
vector the current object is. The following program doesn't compile.
 
#include <vector>
#include <iostream>
 
int main() {
std::vector<int> v={47,11};
for (auto i:v) {
//std::cout<<i<<std::endl;
std::cout<<distance(i,v.begin())<<endl;
}
return 0;
}
Bo Persson <bop@gmb.dk>: Jul 16 11:09AM +0200

On 2015-07-16 10:39, Ralf Goertz wrote:
> }
> return 0;
> }
 
If you have a reference to the element (auto&...), you can compute the
difference between &i and &v[0].
 
 
Bo Persson
Ralf Goertz <me@myprovider.invalid>: Jul 16 12:00PM +0200

Am Thu, 16 Jul 2015 11:09:51 +0200
> > }
 
> If you have a reference to the element (auto&...), you can compute
> the difference between &i and &v[0].
 
Thanks, that works for vector and array, but what about lists or even
sets and maps? I guess I can't add another variable declaration within
the "for" parenthesis like
 
for (auto c=0, i:v) {…}
Ralf Goertz <me@myprovider.invalid>: Jul 16 03:47PM +0200

Am Thu, 16 Jul 2015 05:17:03 -0700 (PDT)
 
> On Thursday, 16 July 2015 13:00:20 UTC+3, Ralf Goertz wrote:
 
[dequoted to make the news server happy]
 
#include <vector> #include <iostream> #include <iterator>
 
int main() {
std::vector<int> v={47,11};
for (auto i:v) {
//std::cout<<i<<std::endl;
std::cout<<std::distance(i,v.begin())<<std::endl;
}
return 0;
}
 
> this code would just output 0 and -1. It does not feel like good way
> for achieving such output, so there must be some sort of point to
> it.
 
Sure, I was merely trying to give a non compiling example (which in the
OP turned out to be non-compilable not only because of the
auto=/=iterator problem). And of course I meant
std::distance(v.begin(),i)
 
 
> Element's reference is cheap to convert to iterator only for
> containers where the elements are stored contiguously in memory
 
I know that and I have to admit that I was stretching the limits. (I
actually need it only for vectors and Bo told me how to do it.) But
anyway, what is bad about the idea that the auto keyword in range based
for loops for container C can also be standing for C::iterator? The
compiler would need to check the first appearence of the (in my case) i
and deduce it is an iterator.
 
 
> int c = 0; for (auto i:v) {...}
 
> If you need to limit scope of c for whatever reason then limit:
 
> {int c = 0; for (auto i:v) {...}}
 
But don't you agree that this approach is somewhat less elegant?
 
> It may be that you need something from Boost.Range or the like but it
> is hard to tell without knowing what you actually want to achieve.
 
Sometimes I need to handle the say 10th element of a vector differently
than the others:
 
for (auto &i:v) {
if (&i-&v[0]==10) {…} // special stuff
else {…} // do ordinary stuff
}
Ian Collins <ian-news@hotmail.com>: Jul 16 11:44AM +1200

fl wrote:
 
> Thanks. As you said, it is a declaration. Good.
> As I am a newbie to C++, I still feel it is different from a normal
> declaration. What role of the throw() in the declaration?
 
As I said above, throw() (noexcept in modern C++) is telling you that
the operators will not throw an exception.
 
--
Ian Collins
Ian Collins <ian-news@hotmail.com>: Jul 16 11:18AM +1200

fl wrote:
> void operator delete[] (void* ptr, const std::nothrow_t& nothrow_constant) throw();
> placement (3)
> void operator delete[] (void* ptr, void* voidptr2) throw();
 
<snip>
 
> 1. In the normal use of delete[], I never see the throw() following it;
> 2. The description does not mention about throw() although the upper part
> has throw()
 
These describe the operators as defined in <new>. The throw() (noexcept
in modern C++) is telling you that the operators will not throw.
 
You don't include the throw() when you use operator delete, it is only
appropriate in the declaration.
 
 
--
Ian Collins
Bo Persson <bop@gmb.dk>: Jul 16 11:03AM +0200

On 2015-07-16 01:36, fl wrote:
> As I am a newbie to C++, I still feel it is different from a normal
> declaration. What role of the throw() in the declaration?
> I hope your further explanation can teach me more on this.
 
The throw-part lists the execeptions the function (or operator) is
allowed to throw. Here the list is empty, meaning that it throws no
exceptions.
 
 
 
Bo Persson
Ian Collins <ian-news@hotmail.com>: Jul 16 09:55AM +1200

The Doctor wrote:
 
Nothing relevant to c.l.c!
 
> All right to essentials on this one.
 
> Using g++ 3.2.3 , Gmake 4.01 and Cmake 2.6.4
 
Why are you using such an old compiler?
 
--
Ian Collins
Paavo Helde <myfirstname@osa.pri.ee>: Jul 15 04:08PM -0500

doctor@doctor.nl2k.ab.ca (The Doctor) wrote in
 
> /usr/source/mysql-5.6.25/sql/filesort_utils.cc:202:
> `return_temporary_buffer'
 
> undeclared in namespace `std'
[...]
> What can I do to compile this?
 
#include <memory> ?
 
hth
Paavo
James Kuyper <jameskuyper@verizon.net>: Jul 15 05:15PM -0400

On 07/15/2015 04:40 PM, The Doctor wrote:
> <unnamed>::try_reserve(std::pair<type*, ptrdiff_t>*, int)':
> /usr/source/mysql-5.6.25/sql/filesort_utils.cc:178: parse error before `>'
> token
 
You're getting a parse error inside a C++ template function. More
specifically, it's a parse error inside the template portion of the C++
syntax for calling a templated function. Why did you think cross-posting
to comp.lang.c would be any help? I know a fair amount of C++, more than
the average person on comp.lang.c - but I can't figure out what's
causing the parse error - so you need a better C++ expert than me. It
might be an interaction between the code you've actually given us, and
the user-defined header files that you didn't give us - so I'd recommend
posting the contents of those files as well. But post it only to
comp.lang.C++
 
> Filesort_buffer::sort_buffer(const Sort_param*, unsigned int)':
> /usr/source/mysql-5.6.25/sql/filesort_utils.cc:202: `return_temporary_buffer'
> undeclared in namespace `std'
 
My copy of the C++2011 standard says that std::get_temporary_buffer<>()
and std::return_temporary_buffer<>() are both declared in <memory>,
which is not one of the headers you #included directly. Is it #included
indirectly through one of the other headers? If not, that would explain
the above error message. If that's the problem, your use of
get_temporary_buffer would probably also have generated such an error
message, if it hadn't been for the parse failure.
doctor@doctor.nl2k.ab.ca (The Doctor): Jul 15 08:40PM

All right to essentials on this one.
 
Using g++ 3.2.3 , Gmake 4.01 and Cmake 2.6.4
 
I get
 
 
Script started on Wed Jul 15 06:45:13 2015
doctor.nl2k.ab.ca//usr/source/mysql-5.6.25$ gmake
 
[ 0%] Built target INFO_BIN
 
...
Scanning dependencies of target sql
 
[ 47%] Building CXX object sql/CMakeFiles/sql.dir/sql_yacc.cc.o
 
[ 47%] Building CXX object sql/CMakeFiles/sql.dir/abstract_query_plan.cc.o
 
[ 47%] Building CXX object sql/CMakeFiles/sql.dir/datadict.cc.o
 
[ 47%] Building CXX object sql/CMakeFiles/sql.dir/debug_sync.cc.o
 
[ 47%] Building CXX object sql/CMakeFiles/sql.dir/derror.cc.o
 
[ 47%] Building CXX object sql/CMakeFiles/sql.dir/des_key_file.cc.o
 
[ 47%] Building CXX object sql/CMakeFiles/sql.dir/discover.cc.o
 
[ 48%] Building CXX object sql/CMakeFiles/sql.dir/field.cc.o
 
/usr/source/mysql-5.6.25/sql/field.cc: In member function `virtual void
 
Field_string::make_sort_key(uchar*, unsigned int)':
 
/usr/source/mysql-5.6.25/sql/field.cc:6886: warning: unused variable `uint tmp'
 
[ 48%] Building CXX object sql/CMakeFiles/sql.dir/field_conv.cc.o
 
[ 48%] Building CXX object sql/CMakeFiles/sql.dir/filesort.cc.o
 
[ 48%] Building CXX object sql/CMakeFiles/sql.dir/filesort_utils.cc.o
 
/usr/source/mysql-5.6.25/sql/filesort_utils.cc: In function `size_t
 
<unnamed>::try_reserve(std::pair<type*, ptrdiff_t>*, int)':
 
/usr/source/mysql-5.6.25/sql/filesort_utils.cc:178: parse error before `>'
 
token
 
/usr/source/mysql-5.6.25/sql/filesort_utils.cc: In member function `void
 
Filesort_buffer::sort_buffer(const Sort_param*, unsigned int)':
 
/usr/source/mysql-5.6.25/sql/filesort_utils.cc:202: `return_temporary_buffer'
 
undeclared in namespace `std'
 
/usr/source/mysql-5.6.25/sql/filesort_utils.cc: In function `size_t
 
<unnamed>::try_reserve(std::pair<type*, ptrdiff_t>*, int) [with type =
 
uchar*]':
 
/usr/source/mysql-5.6.25/sql/filesort_utils.cc:199: instantiated from here
 
/usr/source/mysql-5.6.25/sql/filesort_utils.cc:181: `return_temporary_buffer'
 
undeclared in namespace `std'
 
gmake[2]: *** [sql/CMakeFiles/sql.dir/filesort_utils.cc.o] Error 1
 
gmake[1]: *** [sql/CMakeFiles/sql.dir/all] Error 2
 
gmake: *** [all] Error 2
 
doctor.nl2k.ab.ca//usr/source/mysql-5.6.25$ exit
 
exit
 
 
Script done on Wed Jul 15 07:21:55 2015
 
The code in question is
 
 
/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
 
#include "filesort_utils.h"
#include "sql_const.h"
#include "sql_sort.h"
#include "table.h"
 
#include <stddef.h>
#include <algorithm>
#include <functional>
#include <vector>
 
namespace {
/**
A local helper function. See comments for get_merge_buffers_cost().
*/
double get_merge_cost(ha_rows num_elements, ha_rows num_buffers, uint elem_size)
{
return
2.0 * ((double) num_elements * elem_size) / IO_SIZE
+ num_elements * log((double) num_buffers) * ROWID_COMPARE_COST / M_LN2;
}
}
 
/**
This is a simplified, and faster version of @see get_merge_many_buffs_cost().
We calculate the cost of merging buffers, by simulating the actions
of @see merge_many_buff. For explanations of formulas below,
see comments for get_merge_buffers_cost().
TODO: Use this function for Unique::get_use_cost().
*/
double get_merge_many_buffs_cost_fast(ha_rows num_rows,
ha_rows num_keys_per_buffer,
uint elem_size)
{
ha_rows num_buffers= num_rows / num_keys_per_buffer;
ha_rows last_n_elems= num_rows % num_keys_per_buffer;
double total_cost;
 
// Calculate CPU cost of sorting buffers.
total_cost=
( num_buffers * num_keys_per_buffer * log(1.0 + num_keys_per_buffer) +
last_n_elems * log(1.0 + last_n_elems) ) * ROWID_COMPARE_COST;

// Simulate behavior of merge_many_buff().
while (num_buffers >= MERGEBUFF2)
{
// Calculate # of calls to merge_buffers().
const ha_rows loop_limit= num_buffers - MERGEBUFF*3/2;
const ha_rows num_merge_calls= 1 + loop_limit/MERGEBUFF;
const ha_rows num_remaining_buffs=
num_buffers - num_merge_calls * MERGEBUFF;
 
// Cost of merge sort 'num_merge_calls'.
total_cost+=
num_merge_calls *
get_merge_cost(num_keys_per_buffer * MERGEBUFF, MERGEBUFF, elem_size);
 
// # of records in remaining buffers.
last_n_elems+= num_remaining_buffs * num_keys_per_buffer;
 
// Cost of merge sort of remaining buffers.
total_cost+=
get_merge_cost(last_n_elems, 1 + num_remaining_buffs, elem_size);
 
num_buffers= num_merge_calls;
num_keys_per_buffer*= MERGEBUFF;
}
 
// Simulate final merge_buff call.
last_n_elems+= num_keys_per_buffer * num_buffers;
total_cost+= get_merge_cost(last_n_elems, 1 + num_buffers, elem_size);
return total_cost;
}
 
 
uchar **Filesort_buffer::alloc_sort_buffer(uint num_records, uint record_length)
{
DBUG_ENTER("alloc_sort_buffer");
 
DBUG_EXECUTE_IF("alloc_sort_buffer_fail",
DBUG_SET("+d,simulate_out_of_memory"););
 
/*
For subqueries we try to re-use the buffer, in order to save
expensive malloc/free calls. Both of the sizing parameters may change:
- num_records due to e.g. different statistics from the engine.
- record_length due to different buffer usage:
a heap table may be flushed to myisam, which allows us to sort by
<key, addon fields> rather than <key, rowid>
If we already have a buffer, but with wrong size, we simply delete it.
*/
if (!m_idx_array.is_null())
{
if (num_records != m_idx_array.size() ||
record_length != m_record_length)
free_sort_buffer();
}
 
if (m_idx_array.is_null())
{
uchar **sort_keys=
(uchar**) my_malloc(num_records * (record_length + sizeof(uchar*)),
MYF(0));
m_idx_array= Idx_array(sort_keys, num_records);
m_record_length= record_length;
uchar **start_of_data= m_idx_array.array() + m_idx_array.size();
m_start_of_data= reinterpret_cast<uchar*>(start_of_data);
}
 
DBUG_RETURN(m_idx_array.array());
}
 
 
void Filesort_buffer::free_sort_buffer()
{
my_free(m_idx_array.array());
m_idx_array= Idx_array();
m_record_length= 0;
m_start_of_data= NULL;
}
 
 
namespace {
 
/*
An inline function which does memcmp().
This one turns out to be pretty fast on all platforms, except sparc.
See the accompanying unit tests, which measure various implementations.
*/
inline bool my_mem_compare(const uchar *s1, const uchar *s2, size_t len)
{
DBUG_ASSERT(len > 0);
DBUG_ASSERT(s1 != NULL);
DBUG_ASSERT(s2 != NULL);
do {
if (*s1++ != *s2++)
return *--s1 < *--s2;
} while (--len != 0);
return false;
}
 
 
class Mem_compare :
public std::binary_function<const uchar*, const uchar*, bool>
{
public:
Mem_compare(size_t n) : m_size(n) {}
bool operator()(const uchar *s1, const uchar *s2) const
{
#ifdef __sun
// Usually faster on SUN, see comment for native_compare()
return memcmp(s1, s2, m_size) < 0;
#else
return my_mem_compare(s1, s2, m_size);

No comments: