Sunday, October 28, 2018

Digest for comp.lang.c++@googlegroups.com - 7 updates in 4 topics

Juha Nieminen <nospam@thanks.invalid>: Oct 28 09:31AM

> I have tried the very basic solution of using delete[] in the destructor
> without using smart pointers. That is not the intended solution.
 
Adding a destructor that has a delete[] is not enough. Google
"C++ rule of three".
 
You can bypass the requirements of the "rule of three" if you
simply use std::vector or a similar container (which does implement
the rule of three appropriately).
 
Although it's useful to know that rule of thumb anyway, if you
ever need to do something for which the standard data containers
aren't enough.
Vir Campestris <vir.campestris@invalid.invalid>: Oct 28 09:10PM

On 28/10/2018 09:31, Juha Nieminen wrote:
> Adding a destructor that has a delete[] is not enough. Google
> "C++ rule of three".
 
I'm sure Öö will say "and then rule of five" - see upthread.
 
Andy
Paul <pepstein5@gmail.com>: Oct 28 06:24AM -0700

A standard problem involves transforming a vector of ints by replacing
the ith component by the product of all the entries apart from the ith
component. (I assume the mathematicians' convention that the product
of an empty collection is 1).
Naive attempts can be bugged for the case where the vector has a zero.
Below is my solution with accompanying tests. It seems to work and
I'd be interested to see feedback. It seems to tackle directly
the root of the difficulty by introducing a new type of multiplication
which still retains the necessary information when zero is encountered.
 
// Task is to transform a vector so that each entry is the multiple of all the other
// entries
#include <iostream>
#include <vector>
 
// A struct to handle multiplication which doesn't lose the
// information when zero is encountered.
struct intMult{
intMult(int x = 1) : underlying(x){}
int underlying;
int numZeros = underlying == 0; // Number of zeros that have been encountered in the multiplication
intMult operator * (int y)
{
if(y)
underlying *= y;
else ++numZeros;
 
return *this;
 
}
 
intMult& operator *= (int y)
{
*this = *this * y;
return *this;
}
};
 
void multiplyInVector(std::vector<int>& vec)
{
intMult x;
for(int i = 0; i < vec.size(); ++i)
x *= vec[i];
 
switch(x.numZeros)
{
case 0:
for(int i = 0; i < vec.size(); ++i)
vec[i] = x.underlying / vec[i];
 
return;
 
case 1:
for(int i = 0; i < vec.size(); ++i)
if(!vec[i])
vec[i] = x.underlying;
else
vec[i] = 0;
return;
 
default:
vec = std::vector<int>(vec.size());
 
}
}
 
std::ostream& operator<< (std::ostream& ofs, const std::vector<int>& vec)
{
ofs << "Am printing a vector \n";
for(int i = 0; i < vec.size(); ++i)
ofs << vec[i] << " ";
 
ofs << "\n";
return ofs;
}
 
int main()
{
std::vector<int> x;
std::vector<int> y{0};
std::vector<int> z {-1};
std::vector<int> a {-5, -4, 3, 5, 7};
std::vector<int> b {-5, 0, 3, 5, 2};
std::vector<int> c {-5, 0, 3, 1, 0};
std::vector<int> e {-5, 0, 0, 0 , 1, 2};
multiplyInVector(x);
multiplyInVector(y);
multiplyInVector(z);
multiplyInVector(a);
multiplyInVector(b);
multiplyInVector(c);
multiplyInVector(e);
std::cout << x << y << z << a << b << c << e;
}
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Oct 28 02:46PM +0100

On 28.10.2018 14:24, Paul wrote:
> the ith component by the product of all the entries apart from the ith
> component. (I assume the mathematicians' convention that the product
> of an empty collection is 1).
 
Those numbers will exceed the number of range of C++ integers pretty quick.
 
 
> I'd be interested to see feedback. It seems to tackle directly
> the root of the difficulty by introducing a new type of multiplication
> which still retains the necessary information when zero is encountered.
 
Well it's not exactly a new kind of multiplication. I used the principle
in 1986/87 for Dempster-Schafer evidence combination, together with the
corresponding division operation. Because DS has all these updates of
products of sets and set intersections (it's a combinatorial nightmare).
 
I was later told that it's well known to at least /some/ in mathematics,
but somewhat esoteric, off the beaten path.
 
I speculated at some point whether it could be generalized in a way as
complex numbers, because it's pretty similar to multiplication of
complex numbers in polar representation. That was a dead end, a hunch
that did not pan out. The operations do define a new kind of number-like
entities but these entities don't like addition much, then producing yet
new /kinds/ of entities, and so on, ad nauseam... :)
 
 
> else ++numZeros;
 
> return *this;
 
> }
 
You don't want to modify one of the operands of a multiplication.
 
As a member function make that `const` and don't modify.
 
But better make it a freestanding function, because that better supports
operands that convert implicitly to `intMult`.
 
 
> *this = *this * y;
> return *this;
> }
 
Since the infix `*` modifies its left operand the assignment here is
redundant.
 
But this is where to put the code currently used for infix `*`.
 
Then express infix `*` in terms of `*=`.
 
 
> vec = std::vector<int>(vec.size());
 
> }
> }
 
Better factor out the `/` and `/=` operations also.
 
 
> multiplyInVector(e);
> std::cout << x << y << z << a << b << c << e;
> }
 
 
Well. Maybe express that as a vector of vectors and use a loop?
 
 
Cheers!
 
- Alf
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>: Oct 27 11:45PM -0400

Paul wrote:
 
> Paul
 
Yet another possibility is to use saturated math. e.g.:
 
template <typename B/*base type*/, B L/*low limit*/, B H/*high limit*/>
class SaturatedLimited {
public:
SaturatedLimited(): val_(Limit_(B())) {}
SaturatedLimited(B val): val_(Limit_(val) {}
// operators and functions you need; use native
// B arithmetics, then apply Limit_() to get final result
private:
static B Limit_(B val)
{ return val < L ? L : val > H ? H : val; }
B val_;
};
 
typedef SaturatedLimited<unsigned, 0u, 1000u) NumberOfTests;
 
It is not as expensive as throwing exceptions but the semantics may or
may not be what you want. In case of passing the negative number of
tests to a test!running function it will silently not run a single test
-- which would seem reasonable to some people (mainly mathematicians, I
guess).
 
HTH
-Pavel
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>: Oct 27 11:48PM -0400

Pavel wrote:
...
 
> typedef SaturatedLimited<unsigned, 0u, 1000u) NumberOfTests;
a little correction :-) :
typedef SaturatedLimited<int, 0, 1000) NumberOfTests;
what was I thinking? ...
woodbrian77@gmail.com: Oct 27 05:01PM -0700

"Exception safety is really about when you are in a room
that is completely burning and filled with smoke and fire;
you can drink your coffee and say, 'this is fine' because
I know how to deal with the problem." Jon Cohen from his
Cppcon 2018 talk: "Ensuring Exception Safety Through Testing"
 
https://duckduckgo.com/?q=%22exception+safety%22+cppcon&t=ffab&iax=videos&ia=videos&iai=XPzHNSUnTc4
 
That quote reminds me of these lyrics:
 
"When peace, like a river, attendeth my way,
When sorrows like sea billows roll;
Whatever my lot, Thou hast taught me to say,
It is well, it is well with my soul." Horatio Spafford
 
I liked the talk in general and that was before it hit
me about the parallel.
 
 
Brian
Ebenezer Enterprises - Enjoying programming again.
https://github.com/Ebenezer-group/onwards
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: