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:
Post a Comment