Thursday, October 16, 2014

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

comp.lang.c++@googlegroups.com Google Groups
Unsure why you received this message? You previously subscribed to digests from this group, but we haven't been sending them for a while. We fixed that, but if you don't want to get these messages, send an email to comp.lang.c+++unsubscribe@googlegroups.com.
Paavo Helde <myfirstname@osa.pri.ee>: Oct 15 09:47PM -0500

>>> else if( typeid(*b).name() == typeid(D2).name() )
>>> b1 = new D2(*(reinterpret_cast<D2*>(b1)));
>>> }
 
You can compare directly typeid-s, no need to fetch out the names
(besides, comparing names is not guaranteed to work, they can all be
empty strings legally IIRC).
 
>> to derived.
 
> why not dynamic_cast? It would check if the conversion is valid, static
> cast does not.
 
Dynamic_cast is performed at runtime and can be quite slow. It would be
silly to use dynamic_cast if you have just found out by comparing typeids
that the conversion would be valid (maybe only in debug-build asserts, to
verify you have not made a mistake in the code).
 
A virtual clone function is still the best solution for the cloning
problem: probably faster than the repeated if-else typeid check and also
more scalable and maintainable.
 
Cheers
Paavo
"Tobias Müller" <troplin@bluewin.ch>: Oct 16 06:08AM

> bad from the users point of view seeing this kind of clone function which they never need?
 
> But surely there is a way to hide the clone, like being protected, then
> this would not be a problem.
 
But clone is quite a fundamental function for polymorphic type hierarchies.
I see no value in hiding that.
Also covariant return types make it look much nicer:
 
class Base
{
public:
virtual Base* clone();
};
 
class Derived : public Base
{
virtual Derived* clone();
// instead of:
// virtual Base* clone();
};
 
This is legal if the return type of the derived function is more specific
than the one of the base function. (Which is always true in the case of
"clone")
 
Tobi
JiiPee <no@notvalid.com>: Oct 16 07:14AM +0100

On 16/10/2014 03:47, Paavo Helde wrote:
> You can compare directly typeid-s, no need to fetch out the names
> (besides, comparing names is not guaranteed to work, they can all be
> empty strings legally IIRC).
 
sure
 
> silly to use dynamic_cast if you have just found out by comparing typeids
> that the conversion would be valid (maybe only in debug-build asserts, to
> verify you have not made a mistake in the code).
 
yes, did not notice that. Its like using vector [] instead of at() when
we know the size of the vector.
 
 
> A virtual clone function is still the best solution for the cloning
> problem: probably faster than the repeated if-else typeid check and also
> more scalable and maintainable.
 
Why more scalable? typeid cannot handle all the cases?
JiiPee <no@notvalid.com>: Oct 16 07:51AM +0100

On 12/10/2014 15:02, Paavo Helde wrote:
> array of million strings, this would be a million wasted vtable pointers).
 
> Cheers
> P
 
but I was just talking about a hypothetical situation if it was there. I
do not think string::clone would be a good idea for string's public
users, because if clone is needed in some rare cases it can be done for
str just: string(str)
Paavo Helde <myfirstname@osa.pri.ee>: Oct 16 02:16AM -0500

>> problem: probably faster than the repeated if-else typeid check and
>> also more scalable and maintainable.
 
> Why more scalable? typeid cannot handle all the cases?
 
First, adding a new class can be done in a single code place, no need to
modify the common factory-style cloning function in the old code. Some
shops demand multi-week QA testing if any old code is touched.
 
Second, the new class can be added in a new dynamic load library which
might not even had existed when the common function was written, so could
not be handled by that. Even if it was written, there would appear problems
with circular dependencies (new library should include headers for the old
code, not vice versa).
Paavo Helde <myfirstname@osa.pri.ee>: Oct 16 02:21AM -0500

Paavo Helde <myfirstname@osa.pri.ee> wrote in
> could not be handled by that. Even if it was written, there would
> appear problems with circular dependencies (new library should include
> headers for the old code, not vice versa).
 
Oh, and third: typeid comparing has O(N) complexity in respect of the
number of different classes, a virtual function call has O(1) complexity.
 
Cheers
Paavo
JiiPee <no@notvalid.com>: Oct 16 08:46AM +0100

On 16/10/2014 08:16, Paavo Helde wrote:
> not be handled by that. Even if it was written, there would appear problems
> with circular dependencies (new library should include headers for the old
> code, not vice versa).
 
No just the wording "more scalable" which was confusing me. Isn't it
better to say rather: "better scalable"? Because what you are talking
about here is just that the virtual method is better manageable in the
future....its not that the factory is not able to do the same things,
its just that the virtual method is the better way to do it.
 
Or are there situations where the factory is not able to do (with good
or bad coding methods) the clones and it can *only* be done by the
virtual method? That was my original question.
 
If the same thing can be done with both methods (that we get the clone),
then I would not say "is more scalable = more able to be changed in size
(where the size is the ability to get clones)".
JiiPee <no@notvalid.com>: Oct 16 08:52AM +0100

On 16/10/2014 08:16, Paavo Helde wrote:
> not be handled by that. Even if it was written, there would appear problems
> with circular dependencies (new library should include headers for the old
> code, not vice versa).
 
Can you show me a simple code example where the clone can only be done
by virtual and not factory method?
Paavo Helde <myfirstname@osa.pri.ee>: Oct 16 11:24AM -0500

> No just the wording "more scalable" which was confusing me. Isn't it
> better to say rather: "better scalable"?
 
Sorry, not a native speaker - these terms seem the same to me.
 
Cheers
Paavo
"Öö Tiib" <ootiib@hot.ee>: Oct 16 09:26AM -0700

On Thursday, 16 October 2014 10:52:40 UTC+3, JiiPee wrote:
> > code, not vice versa).
 
> Can you show me a simple code example where the clone can only be done
> by virtual and not factory method?
 
He wrote about modules. C++ does not have modules in its language
description but that is a lie. In practice lot of applications (written in whatever
programming languages) often use modules written in C++. Modules should
not be tightly coupled with each other in all directions otherwise the whole
point of having modules is lost and you have to link them all together
everywhere.
 
Imagine there is module where base class "Tool" is defined. Imagine it has also
"ToolFactory". Now time passes and you need to develop module for certain
application that needs a tool "Gallows". Result is dependency knot since
"ToolFactory" needs to learn to clone "Gallows". Both modules need to be
linked to all applications that deal with whatever "Tool"s. Crap design since
"Gallows" are used rather rarely. That can be avoided if only "Gallows" know
how to clone "Gallows".
Paavo Helde <myfirstname@osa.pri.ee>: Oct 16 11:53AM -0500


> Can you show me a simple code example where the clone can only be done
> by virtual and not factory method?
 
Here it goes. Assume that the build process checks out and builds
projects one-by one, in the order specified somewhere else (I have used
such a process for many years in the past), to avoid any fancy ideas of
including b.h in the base library (which would by all wrong conceptually
anyway).
 
 
// base library (DLL)
// a.h
class A {
public:
virtual ~A() {}
virtual A* clone() const = 0;
};
 
void foo(A* x);
 
// a.cpp
void foo(A* x) {
A* y = x->clone();
delete y;
}
 
// -------------------------------------
 
// extension library (DLL) - link to base library
// b.h
//#include <BaseLibrary/a.h>
 
class B: public A {
public:
virtual B* clone() const override;
};
 
// b.cpp
B* B::clone() const {
return new B(*this);
}
 
// -------------------------------------
 
// main program - link to base library and extension library
// main.cpp
 
//#include <BaseLibrary/a.h>
//#include <Extensionlibrary/b.h>
 
int main() {
A* x = new B();
foo(x);
delete x;
}
JiiPee <no@notvalid.com>: Oct 16 06:11PM +0100

On 16/10/2014 17:24, Paavo Helde wrote:
> Sorry, not a native speaker - these terms seem the same to me.
 
> Cheers
> Paavo
 
They have a bit different meaning. For example making more cars is
different than making better cars. If two people make both 10 cars then
its only a matter who made better cars. If the other one makes 10 cars
and the other one 15 cars, then its a matter of who made better cars
plus who made more cars.
JiiPee <no@notvalid.com>: Oct 16 06:17PM +0100

On 16/10/2014 17:26, 嘱 Tiib wrote:
> linked to all applications that deal with whatever "Tool"s. Crap design since
> "Gallows" are used rather rarely. That can be avoided if only "Gallows" know
> how to clone "Gallows".
 
I do not disagree with virtual method being better. I am only saying
that I cannot see that there would be a situation where the factory
cannot produce the clone and only the virtual method can do it. But
Paavo says he has an example (although there is no explanation), so I ll
try to check that.
JiiPee <no@notvalid.com>: Oct 16 06:20PM +0100

On 16/10/2014 17:53, Paavo Helde wrote:
> such a process for many years in the past), to avoid any fancy ideas of
> including b.h in the base library (which would by all wrong conceptually
> anyway).
 
and why factory system cannot do this?
JiiPee <no@notvalid.com>: Oct 16 06:35PM +0100

On 16/10/2014 18:30, Martin Shobe wrote:
 
> In casual conversation, either works fine. If I was being formal I'd
> say, "... also scales and maintains better ..."
 
> Martin Shobe
 
more apples and better apples are a bit different to me :) ... that was
the confusion I had.
Do we have more apples, or not more but just better apples....
Paavo Helde <myfirstname@osa.pri.ee>: Oct 16 12:38PM -0500

>> including b.h in the base library (which would by all wrong conceptually
>> anyway).
 
> and why factory system cannot do this?
 
Well, how do you propose to do this? Maybe you could try to write a
replacement for the foo() function which makes a copy of the passed object
without using the virtual clone() function.
Paavo Helde <myfirstname@osa.pri.ee>: Oct 16 12:42PM -0500

> its only a matter who made better cars. If the other one makes 10 cars
> and the other one 15 cars, then its a matter of who made better cars
> plus who made more cars.
 
With cars I can see the difference! :) But not with "scalable", here I feel
more==better.
Evan Sebastian <evanlhoini@gmail.com>: Oct 16 09:28AM -0700

Hello,
 
Have someone encountered the assertion error when working with boost unordered_set (and set)?
 
The value type used is std::int64_t
The assertion which fails is
 
mlf >= minimum max load factor
 
Which is the first statement in the function min_buckets_for_size in this header file.
 
http://www.boost.org/doc/libs/1_50_0/boost/unordered/detail/table.hpp
 
 
Details :
I have two projects in Visual C++ 2013 (x86), one for library and one for native unit testing as per usual.
 
In the project, there is a class that defines some resource When I changed one of its member's type from vector to unordered_set (and fixed the regression it caused until it builds fine), my unit testing project failed to run with this message (https://connect.microsoft.com/VisualStudio/feedback/details/786792/c-unit-testing-failed-to-set-up-the-execution-context-to-run-the-test).
 
 
At first I used stl unordered set, so I tried changing to boost::unordered_set to see if that makes any difference. Then I get the assertion error.
 
In the code itself, the said member only undergo 1. initialization via C++11 initializer list, 2. comparison, 3. insertion.
 
The builds are fine, and the program executable doesn't show any unintended behavior.
Unfortunately, I can't show the complete code since this is a private project.
 
I would appreciate any help or suggestion on this problem.
 
------
Evan Sebastian
"Öö Tiib" <ootiib@hot.ee>: Oct 16 10:12AM -0700

On Thursday, 16 October 2014 19:28:45 UTC+3, Evan Sebastian wrote:
 
> Unfortunately, I can't show the complete code since this is a private project.
 
Try to make minimal example that reproduces the issue.
Constructing it typically reveals where the defect is in your private code.
If it does not for you then at least you can post that thing since it is
not complete code of your private project anymore.
Robert Hutchings <rm.hutchings@gmail.com>: Oct 16 08:47AM -0500

I was given this code yesterday:
 
 
#ifndef _MEMOIZE_H_
#define _MEMOIZE_H_
 
#include <tuple>
#include <map>
 
template < typename T > struct Memoize
{
template <typename... Args> static auto Func(Args... args)
-> decltype(T::Func(std::forward<Args>(args)...))
{
using INPUT = std::tuple<Args...>;
 
using RESULT = decltype(T::Func(std::forward<Args>(args)...));
 
static std::map< INPUT, RESULT > repository;
 
auto key = std::make_tuple(std::forward<Args>(args)...);
 
auto it = repository.find(key);
 
if (it != repository.end())
{
return it->second;
}
 
else
{
auto result = T::Func(std::forward<Args>(args)...);
 
repository[key] = result;
 
return result;
}
}
};
 

No comments: