puzzlecracker ha scritto:
>> Long answer: you may find it hard to swallow, but C++ has no concept of
>> vtable. Moreover the language is intentionally designed so that you
>> can't take the address of a member function (you can obtain a
>> pointer-to-member-function, but that is *not* an address). So C++ was
>> deliberately designed to hide the information you seek.
>
> Can you take an address of a non-member function? I believe you
> cannot. What's the logic behind it?
Sure you can. If f() is a non-member function or a static member
function, &f (or simply f) gives you a pointer to it. On most platforms,
a pointer to a function is just the address of the function. That is not
true for non-static member functions.
> You can approximate the address of the function by looking at the
> local stack:
>
> void foo(){
>
> char a;
>
> }
>
> Steps:
> 1. Figure out whether stack is increasing or decreasing.
> 2. char is equal to 2 bytes, hence the function's location starts
> before (or after that), plus minus off-set
The problem is that C++ doesn't even have the concept of stack.
> However, as mentioned before, you cannot portably perform these steps.
>
Right.
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
compare two objects, if they have the same vtable
Policy-based class design or inheritance?
On 30 Set, 20:59, "Martin T." <0xCDCDC...@gmx.at> wrote:
> Vincent wrote:
> > Hi all,
> > suppose we can choose between two approaches:
> > 1) First approach (policy-based class design)
>
> > template
> > class A {
> > ...
> > public:
> > void print() {
> > OutputPolicy::print("...");
> > }
> > };
> > (...)
>
> > 2) Second approach (classic inheritance)
> > class A {
> > ...
> > public:
> > virtual void print() = 0;
> > }
> > (...)
> > Instinctively I tend toward the first approach. Inheritance is
> > undoubtedly a "pillar" of object-oriented programming, but if possible
> > I always look for an alternative design. (Inheritance introduces
> > issues not always obvious: it's really an "is a" model? the base class
> > should be made abstract? the polymorphic use of the class should be
> > allowed? the inheritance should be of interface or of implementation?
> > and so on.)
>
> > What alternative do you prefer?
>
> Well. If you need polymorphic, that is use type A somewhere where you do
> not want/can use A as a template, you're stuck with solution #2, yes?
Yes.
> If, on the other hand, A is only ever used as the concrete type A
> you can templatize the user code, then #1 looks very compelling.
Yes, I agree. Personally, I find the policy-based design clear and
elegant. It is also relatively simple, while, IMO, the concept of
"inheritance" require a-not-so-trivial-to-obtain experience (trials
and errors).
> Personally, I would never use #1 if there are no strong reasons why #2
> is clearly worse, because at my current environment it would just
> confuse people.
In my opinion solution #2 is not so bad, but #1 is better. Why?
Because it is clear, elegant and not error prone (no need to think of
virtual tables, pure virtual functions, polymorphism, and so on).
What do you think?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
curiously recurring template pattern (CRTP) and types
On Sep 29, 10:52 am, Alberto Ganesh Barbati
wrote:
> A non-virtual member function of a class template is instantiated only
> if you use it and the point of instantiation (PoI) is right before the
> first use, not when the class template is instantiated. It's only at the
> PoI of the *member function* (not of the class template) that the type
> is actually substituted in the function body and the compiler checks if
> T::X is really a type as you promised.
The PoI of a non-virtual member function of a class template is not
right *before* the first use, it is in the enclosing namespace of the
function that first uses it, right after the definition (or
declaration if triggered by a default argument) of the function that
uses it. On the other hand, the PoI of a virtual member function is
often *before* its use since the PoI of a virtual member function is
right after the PoI of the enclosing class template specialization
(since virtual member functions are instantiated implicitly when the
class template specialization is instantiated - right?) - yuk - i
dunno if that's clear - but this language is just nutty. Eitherway -
check out 14.6.4.1 in the standard, and let me know if u disagree.
This is what I think should be going on:
void g(int);
template
friend void g(T,char=0) { }
virtual void vf() { g(T()); }
void f() { g(T()); }
};
namespace N {
//1 - PoI for Base
//1 - PoI/D for void g(Derived, char) - but only found by ADL?
//1a - PoI Base
struct Derived : Base
void g(Derived); // never gets called
virtual void vf() { }
};
void g(Derived);
} // End ns N
//2 PoI for Base
//2 PoI/D for void g(int,char) - only found by ADL - i.e. never -
//2a PoI for Base
int main()
{
Base
b.f(); // no Ambiguity! ask two-phase harvey-dent why -
N::Derived d;
d.f(); // Ambiguous!
}
//3 POI for Base
forget two-phase)
//3 POI for Base
Of course since the standard apparently allows the compiler to move
PoIs to the end of the translation unit, many compilers might complain
that both Base
Base
context is used for lookup - and the only declaration in the defintion
context is void g(int) - the friend becomes part of the instantiation
context - which is only searched if T was a UDT.
Eitherway, this example is ill-formed, since the set of PoIs for
Base
Perhaps I shouldn't have brought 2-phase into it - but it's too late
now - so what do others think of the interpretation?
fun stuff ;)
regards,
Faisal Vali
Radiation Oncology
Loyola
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Get point is moving backwards.
RyanMcCoskrie ha scritto:
> I'm working on a small assembler for a virtualised architecture on
> Linux.
>
> This is the central loop:
>
> while( !input.eof() ){
> input >> str;
Never use eof() unless you really know what it does and I can assure you
that it doesn't do what you think it should do. Use this instead:
while (input >> str) {
(hint: this implicitly tests fail() instead of eof(), which is the
correct thing to do in this case)
>
> if( str == "set") set();
> //etcetera...
>
> Set then goes on to gather information from the input file (a global
> variable)
> and adds the results to the output buffer.
> Seems good in theory.
>
> When I run this though on the second iteration of the central loop the
> get point has defaulted
> back to zero.
What is the "get point"?
> Is this meant to happen or should I file a bug report to the FSF?
>
You weren't clear enough to let me understand what it's happening, but
it looks precisely like something that could be caused by using eof()
instead of fail().
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
streaming io
On Sep 30, 12:29 pm, Sebastian Karlsson
> Hi, I can't seem to be able to find if the file streams available in
> std are streaming in the sense that they're asynchronous. I'd like to
> read for example 100 bytes, let that call block until 100 bytes is
> read. And then while I process those 100 bytes, the underlying stream
> object would continue to fill up the buffer. And if they aren't
> asynchronous, is there any good implementation of streaming io out
> there which is somewhat portable?
A stream is an abstraction of a source or sink of data. A stream does
not imply a non-blocking interface. There is no non-blocking IO in the
C++ standard library or language, nor does standard-only C++ give you
the necessary building blocks to write your own.
There may be third party tools which abstract to a common denominator
which compiles on all platforms which actually support non-blocking
IO. I don't know offhand.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
The memory size of a method?
mojumbo
> I am passing around a structure, say:
>
> tsBob
> {
> int a;
> int b;
> int bobMethod(bool lb);
> };
>
> I would like to make sure the structure is aligned along a 64-bit
> boundary (it's being thrown around the system). I assumed it was the
> size of a pointer (32-bits) but when I googled & wrote a little driver
> (See below) it was only 1 byte. Since I can't believe this does
> anyone have an answer?
>
> int main(int argc, char* argv[])
> {
> tsBob aBob;
>
> cout << "Size of bobMethod is " << sizeof(aBob.bobMethod) << endl;
>
> return 0;
> }
I suspect you're unintentionally using some compiler extension.
gcc, when invoked as a C compiler, allows sizeof to be applied to
expressions of function type (or to type void), yielding the value 1.
This is an unfortunate side effect of a gcc extension that allows
pointer arithmetic on void* and pointer-to-function types; the
pointers are treated as byte pointers, so adding N advances the
pointer by N bytes in memory.
g++ doesn't seem to support this extension, but it's possible that
some older version did.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
maximum length of template argument list
Hi,
in my pursue of an efficient polimorfic container I finally decided
to use the MPL vector from boost. I have successfully extended the
container to handle ca. 200 elements, but I wonder --
whether anybody knows what is the maximum length of the template
argument list (as it could be the limitation of my endeavours.)? I have
skimmed through the C++ 98 spec, but to no avail: could it be compiler
dependent?
Regards,
Marek
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Policy-based class design or inheritance?
On 29 Set, 21:04, puzzlecracker
> On Sep 29, 12:29 pm, Vincent
> > Hi all,
> >
> > suppose we can choose between two approaches:
> >
> > 1) First approach (policy-based class design)
> > [CUT]
> >
> > 2) Second approach (classic inheritance)
> > [CUT]
> >
> > Instinctively I tend toward the first approach. Inheritance is
> > undoubtedly a "pillar" of object-oriented programming, but if possible
> > I always look for an alternative design. (Inheritance introduces
> > issues not always obvious: it's really an "is a" model? the base class
> > should be made abstract? the polymorphic use of the class should be
> > allowed? the inheritance should be of interface or of implementation?
> > and so on.)
>
> > What alternative do you prefer?
>
> > Vincent
>
> It seems that both approaches need to include A.h file, hence original
> coupling persist. I would use stratagy and passing a pointer (evia
> ctor or setter) to AToStderr class
>
> class OutputToStderr {
>
> static void setPrinter(Printer *printer) {
> _printer=printer;
> }
> print();
> private:
> static Printer _printer
> };
True, this is another solution, but in my specific case I don't need
the strategy pattern, because its
peculiarity is to select an algorithm "at runtime", while I want
select it "at compile time" (hence the idea of use a policy).
The fact that through the strategy pattern I can remove the #include
"A.h" in my case does not involve major benefits.
Vincent.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
streaming io
Hi, I can't seem to be able to find if the file streams available in
std are streaming in the sense that they're asynchronous. I'd like to
read for example 100 bytes, let that call block until 100 bytes is
read. And then while I process those 100 bytes, the underlying stream
object would continue to fill up the buffer. And if they aren't
asynchronous, is there any good implementation of streaming io out
there which is somewhat portable?
// Sebastian Karlsson
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Get point is moving backwards.
I'm working on a small assembler for a virtualised architecture on
Linux.
This is the central loop:
while( !input.eof() ){
input >> str;
if( str == "set") set();
//etcetera...
Set then goes on to gather information from the input file (a global
variable)
and adds the results to the output buffer.
Seems good in theory.
When I run this though on the second iteration of the central loop the
get point has defaulted
back to zero.
Is this meant to happen or should I file a bug report to the FSF?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Anonymous Namespace or Static
Hi,
I am little confused about the use of anonymous namespace over
traditional static keyword for restricting its use in within a
translation unit. I read that names in anonymous namespace have
external linkage as opposed to internal linkage by static keyword.
However since the name cannot be used anyway outside the unit how does
it matter.
Can anyone please help?
Thanks.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Policy-based class design or inheritance?
Vincent wrote:
> Hi all,
> suppose we can choose between two approaches:
> 1) First approach (policy-based class design)
>
> template
> class A {
> ...
> public:
> void print() {
> OutputPolicy::print("...");
> }
> };
> (...)
>
> 2) Second approach (classic inheritance)
> class A {
> ...
> public:
> virtual void print() = 0;
> }
> (...)
> Instinctively I tend toward the first approach. Inheritance is
> undoubtedly a "pillar" of object-oriented programming, but if possible
> I always look for an alternative design. (Inheritance introduces
> issues not always obvious: it's really an "is a" model? the base class
> should be made abstract? the polymorphic use of the class should be
> allowed? the inheritance should be of interface or of implementation?
> and so on.)
>
> What alternative do you prefer?
Well. If you need polymorphic, that is use type A somewhere where you do
not want/can use A as a template, you're stuck with solution #2, yes?
If, on the other hand, A is only ever used as the concrete type A
you can templatize the user code, then #1 looks very compelling.
Personally, I would never use #1 if there are no strong reasons why #2
is clearly worse, because at my current environment it would just
confuse people.
br,
Martin
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
compare two objects, if they have the same vtable
Alberto Ganesh Barbati schrieb:
> Albert Zeyer ha scritto:
>> Hi,
>>
>> I have an easy base class:
>>
>> class Base {
>> virtual void func();
>> }
>>
>> And I want to do an easy type-equality check based on the vtable-entry
>> of func.
>>
>> Basically, I want to do the following:
>>
>> bool operator==(const Base& o1, const Base& o2) {
>> return &o1.func == &o2.func;
>> }
>>
>> How can I do this? I don't want to add any RTTI to the project as it is
>> not really needed here (because in my case, it's enough to just compare
>> the vtable).
>>
>
> Short answer: you can't do that in a portable way.
>
> Long answer: you may find it hard to swallow, but C++ has no concept of
> vtable. Moreover the language is intentionally designed so that you
> can't take the address of a member function (you can obtain a
> pointer-to-member-function, but that is *not* an address). So C++ was
> deliberately designed to hide the information you seek.
>
> Ganesh
>
That is what I also found out after some research. I thought there is
perhaps some trick to do this.
Right now, I have solved this by doing the following:
template
_dst* simple_dyn_cast(_src* ptr) {
_dst tmp;
if(memcmp(ptr, &tmp, sizeof(_src)) == 0) { // compare vtable
return (_dst*)ptr;
}
return NULL;
}
template
_dst* simple_dyn_cast(_src* ptr, _dst* base) {
if(memcmp(ptr, base, sizeof(_src)) == 0) { // compare vtable
return (_dst*)ptr;
}
return NULL;
}
That works as long as the Base class contains a set of virtual functions
and no member variables. (At least it seems to work on various GCC
versions under varios systems and on MSVC++.)
I need such a thing, because my Base class also have an operator==.
I can do now:
class Derived : public Base {
void func() {}
bool operator==(const Base& obj) {
const Derived* d = simple_dyn_cast
if(!d) return false;
// compare other stuff
}
}
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Overloading on return value (with a trick)
On Sep 24, 11:29 pm, Ulrich Eckhardt
> Really? You first need both the 666 and the 'E', which are IIUC the results
> of the two function calls, so typically one of them is wasted. That's also
> why I'd use a less complicated one:
>
> int int_function();
> char char_function();
>
> struct proxy {
> operator int() const {
> return int_function();
> }
> operator char() const {
> return char_function();
> }
> };
>
> proxy function() {
> return proxy();
> }
Your idea is very interesting, just amazing in fact, I've expanded it
a bit, probably it will be useful for somebody. Using it, it is
possible to provide any number of overloading functions, for example
with the following way:
char f_char()
{std::cout<<"f_char()\n";return char();}
int f_int()
{std::cout<<"f_int()\n";return int();}
short f_short(int) //!! Function accepts parameter
{std::cout<<"f_short()\n";return short();}
char a = f(f_char); // prints "f_char()"
int b = f(f_char, f_int); // prints "f_int()"
char c = f(f_char, f_int); // prints "f_char()"
short d = f(f_char, boost::bind(f_short,5)); //!! Binders
allowed // prints "f_short()"
int e = f(f_int, f_short); //!! Function without binded parameter
allowed // prints "f_int()"
char f = f(f_char, f_char); //!! Cause compilation error because of
ambiguity
So, the implementation itself below (yeah, I know, this code is not
ideal :-) ):
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// Maximum number of overload variants
#ifndef RETTYPE_OVERLOAD_MAX_COUNT
#define RETTYPE_OVERLOAD_MAX_COUNT 10
#endif
namespace{
// Just a static check used to verify that all types in the
overloads list are unique
namespace static_check{
template
struct check{inline check(){}};
template<>
struct check
};
#define STATIC_CHECK(expr,msg)
static_check::check
// Helper function used to check if all types in the sequence are
unique
template
struct is_unique : boost::mpl::and_<
boost::mpl::not_<
boost::mpl::contains<
typename boost::mpl::pop_front
typename boost::mpl::front
>
>,
is_unique<
typename boost::mpl::pop_front
>
>
{};
template<>
struct is_unique
{};
// Just a helper used to get result type both from binded functors
and functions
template
struct get_result_type_impl
{
typedef typename boost::function_traits
};
template
struct get_result_type_impl
{
typedef typename T::result_type result_type;
};
template
struct get_result_type
{
typedef typename get_result_type_impl<
typename boost::mpl::and_<
boost::is_pointer
boost::is_function
>::type,
T
>::result_type result_type;
};
// Trick kernel, provides type cast function for each type in the
list
template
struct proxy_impl : proxy_impl<
typename boost::mpl::front
typename boost::mpl::pop_front
{
typedef proxy_impl<
typename boost::mpl::front
typename boost::mpl::pop_front
proxy_impl(type t,const base& b)
:t_(t),base(b)
{}
operator typename get_result_type
{
return t_();
}
private:
const type t_;
};
template
struct proxy_impl
{
proxy_impl(type t)
:t_(t)
{}
operator typename get_result_type
{
return t_();
}
private:
const type t_;
};
template
struct proxy : proxy_impl<
typename boost::mpl::front
typename boost::mpl::pop_front
{
STATIC_CHECK(is_unique
typedef proxy_impl<
typename boost::mpl::front
typename boost::mpl::pop_front
> base;
};
}
// Basic variant, only one type cast provided
template
typename proxy
{
return proxy
}
// Generate code for possible overloads
#define RETTYPE_generate(z,n,unused) \
template
typename proxy< \
boost::mpl::list
>::base \
f(BOOST_PP_ENUM_BINARY_PARAMS(n,T,t)) \
{ \
return typename proxy< \
boost::mpl::list
>::base(t0,f(BOOST_PP_ENUM_SHIFTED_PARAMS(n,t))); \
}
BOOST_PP_REPEAT_FROM_TO(2,RETTYPE_OVERLOAD_MAX_COUNT,RETTYPE_generate,~)
#undef RETTYPE_generate
If somebody have anything to add concerning code quality or there is a
bug in this code, please, let me know.
----
Cheers,
Dmitry,
Mera Networks (http://meranetworks.com/)
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Are throwing default constructors bad style, and if so, why?
On Sep 26, 7:52 pm, Andre Kaufmann
> JoshuaMaur...@gmail.com wrote:
> > [...]
> >> There are 3 golden rules regarding code performance one should follow:
>
> >> a) Measure
> >> b) Measure
> >> c) Measure
>
> > I disagree. That's going too far. For example, if I need an algorithm
> > to sort data, and I have no guarantees on the order of the incoming
> > data, I'm going to use std::map. It may not be the fastest thing
> > available, but I do know that it will be faster that using a sorted
> > std::vector for any non-trivial case.
>
> Don't get me wrong - measuring can't replace good design and choosing
> the right algorithm for a specific task.
> It should only replace assumptions:
>
> E.g.:
>
> a) I assumed that cout isn't slower than printf - rather the contrary
> b) I assumed that iostreams aren't that slower than C file functions
> > You cannot measure everything in the real world. Now, this is science,
> > so everything is independently verifiable, but you don't verify the
> > wheel every time you design a car.
I've heard this often. Some implementations do implement and compile
the iostreams poorly. Now, technically, with a crazy awesome compiler,
as the types are statically available, the compiler could do better
with iostreams. However, from what little I've read, this isn't true
in the real world in general. The reasons include (but are not limited
to) printf has to parse the format string at runtime, iostreams have
some virtual call overhead to deal with in their underlying buffer,
iostream relies upon good lining of the operator<< and >>, etc. This
is a topic unto itself on which I'm ill prepared to speak, so I'll let
it be with just that.
> You can't measure everything for sure - but how often is an obvious
> faster algorithm measured to be really faster ?
> And sometimes the measures are done only once for a small example and
> not for the released code.
Either way, there is no general consensus that yes, compilers do
implement iostreams as well as printf, so your counter-example to my
argument is somewhat flawed.
I'm talking about basic asymptotic analysis and other equivalently
simply analysis, like don't compute the same value twice in a row. If
it takes no more programmer time to do it with the known faster
algorithm, and it's just as simple, modular, changeable, etc., then
use the faster algorithm.
> On the other side it shouldn't be exaggerated. A developer should have a
> basic knowledge regarding performance of algorithms and code/cpu and
> then he should concentrate on the hot spots and not waste too much time
> to measure the performance of code which isn't relevant.
>
> > By the same token, I know that if I add a bunch of unused code to the
> > end of my executable, I know it won't affect runtime performance in a
> > system with virtual memory. The unused pages of the executable will
> > stay paged out to disk, requiring no runtime cost at all.
I must apologize as I was unable to replicate my "minimal" testing
which showed visual studios 2005 handled exceptions properly, that is
with the table method and ~0 runtime overhead if you don't throw.
Googling for information has been tedious. The best source of
information I can find is this year old blog from MS
http://blogs.msdn.com/vcblog/archive/2007/08/10/the-future-of-the-c-language.aspx
In it they explain they still use the "code method" to implement
exceptions, though on x64 platforms they use the table approach. Maybe
I did my previous testing on an x64 machine. My recent testing was on
my 32 bit laptop.
> O.k. let's try to measure a small sample:
>
> ###################
> #### sample1: #####
>
> class error : public std::exception
> {
> public: error(const char* whatInit) : what(whatInit) {}
> std::string what;
>
> };
>
> int value = 100;
> int calc = 0;
> void foo()
> {
> calc+= value; // only to reduce optimizer impact
> if (value <= 1000) return;
> if (value > 10000) throw error("value larger 10000");
> if (value > 1000) throw error("value larger 1000");
>
> }
>
> void foomain() { foo(); }
>
> ###################
> #### sample2: #####
>
> int fox()
> {
> calc+= value;
> if (value <= 1000) return 0;
> if (value > 10000 ) return 2;
> if (value > 1000) return 1;
>
> }
>
> bool foxmain()
> {
> int result = fox();
> switch (result)
> {
> case 0: return true;
> case 1: { cout << "value larger 1000" << endl; break; }
> case 2: { cout << "value larger 10000" << endl; break; }
> }
> return false;
>
> }
>
> Sample1 should be slightly faster, because basically the code is the
> same, but sample 1 uses exceptions and returns no value to be evaluated.
> And additionally the exception code isn't executed and should have no
> impact.
>
> Results (calling the functions foomain, foxmain 1000000 times)
>
> for cpp compiler (Windows) a:
>
> Sample1: 2291 ms
> Sample2: 801 ms
>
> for cpp compiler (Windows) b:
>
> Sample1: 800 ms
> Sample2: 601 ms
>
> Now replacing the lines in sample1:
>
> if (value > 10000) throw error("value larger 10000");
> if (value > 1000) throw error("value larger 1000");
>
> by
>
> if (value > 10000) throw "value larger 10000";
> if (value > 1000) throw "value larger 1000";
>
> gives the following result for compiler a):
>
> Sample1: 823 ms
> Sample2: 801 ms
>
> Obviously the exception code had an impact.
>
> It might be a lame example and not a proof for more complex programs - I
> know. But what about the general assumption exceptions to be at least
> not slower - will that be generally true for complex programs too, if
> it's not (generally) true for a small example ?
I would love to see what happens when the loop is moved inside the
program. I would suspect you're measuring not what you want, that
you're measuring startup and teardown time of the process, not the
difference between return codes and exceptions.
Moreover, I think there's another problem to your example. In both
cases you have an if check, one if to determine if you're going to
throw an exception, the other if you're going to return an error code.
In the return code case, there's another if statement to check the
returned value. I'd expect that the return code case would have one of
those two if statements optimized away with decent inlining. Thus it's
probably not a good example of exceptions vs error return codes in the
real world.
I'm guessing that a virtual function call would inhibit inlining in
this case. I'll do a quick test to see if my inlining suspicion is
correct, and how exceptions fare.
(20 min later)
Confirmed and confirmed. I got on a company Linux 64 box with g++
3.4.3. (Yeah I know my company needs to upgrade.) Here's my source:
// **** **** **** **** ****
#include
#include
#include
using namespace std;
class TestInterface
{
public:
enum ReturnCodeT { Success = 1, Failure = 2 };
virtual void testExceptions(int a, int b, int targetSum) = 0;
virtual ReturnCodeT testReturnCodes(int a, int b, int targetSum) =
0;
ReturnCodeT testReturnCodes_2(int a, int b, int targetSum)
{ if (a + b == targetSum)
return Failure;
return Success;
}
};
class TestImpl : public TestInterface
{
public:
virtual void testExceptions(int a, int b, int targetSum)
{ if (a + b == targetSum)
throw 1;
}
virtual ReturnCodeT testReturnCodes(int a, int b, int targetSum)
{ if (a + b == targetSum)
return Failure;
return Success;
}
};
int main(int argc, char ** argv)
{
if (argc != 3)
return 1;
int arg1;
if (! ( stringstream(argv[1]) >> arg1))
return 1;
int arg2;
if (! ( stringstream(argv[2]) >> arg2))
return 1;
TestInterface * x = new TestImpl();
clock_t t0 = clock();
for (int i=0; i
cout << "Failure returned (1)" << endl;
clock_t t1 = clock();
for (int i=0; i
{ x->testExceptions(i, j, arg2);
} catch (int & )
{ cout << "Exception caught" << endl;
}
}
clock_t t2 = clock();
for (int i=0; i
cout << "Failure returned (2)" << endl;
clock_t t3 = clock();
cout << "Not-inlined return codes "
<< double(t1 - t0) / double(CLOCKS_PER_SEC)
<< endl;
cout << "Exceptions "
<< double(t2 - t1) / double(CLOCKS_PER_SEC)
<< endl;
cout << "Inlineable return codes "
<< double(t3 - t2) / double(CLOCKS_PER_SEC)
<< endl;
}
// **** **** **** **** ****
[prompt]$ g++ foo.cpp -O3 -fomit-frame-pointer
[prompt]$ ./a.out 60000 -1
Not-inlined return codes 9.5
Exceptions 8.69
Inlineable return codes 4.07
I also swapped the order of the tests to help make sure that the tests
weren't otherwise measuring some sort of startup time, and the results
were the same.
Now, I admit this is a somewhat trivial example. I never claimed that
exceptions would make your program noticeably faster in a majority of
cases. I will claim that properly used with a non-POS compiler (e.g.
not visual studios), they can make your program faster, and if
properly used, they will almost never make your program slower.
> > The "measure, measure, measure" rule is often misapplied. You should
> > always use the correct data structures and algorithms the first time.
> > Don't just use a linear search and say "Oh, it's ok. We'll measure it
> > later to see how bad it is."
>
> It seems to be often obvious. But a linear search might be faster than a
> binary search for small lists. For an experience developer this might be
> obvious too. An unordered map should be faster than a normal map too.
> But should it generally be used ?
>
> > The distinction is implementing the code with the binary search is
> > just as easy, flexible, correct, etc., than writing it with the linear
> > search, so prefer the better algorithm.
>
> The better algorithm has some downsides, or we wouldn't have and use
> std::list ? Would we ?
> When is it better to use an vector due to cache locality than using a map ?
Your example of list vs vector vs map shows that you do not understand
the basics of algorithms, or that you are purposely misconstruing my
statements. There is no single best. Best is defined in terms of the
operations you're going to do on the data.
For example, if you need to sort input data of any nontrivial size
given no information on its starting order, then you should use
std::map instead of std::vector. If you're just going to store some
input data, perform some operations on each individually, then dump it
somewhere, then use a std::vector. If you're going to do a lot of
inserts and removes from the middle, or splicing, etc., then use
std::list.
By a (not very) similar token, I like exceptions over error return
codes for stuff like "out of memory". It simplifies my life as a
programmer, it allows me to write less code, and it gives me
(slightly) faster code.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
compare two objects, if they have the same vtable
On 29 Sep, 18:29, Albert Zeyer
> Hi,
>
> I have an easy base class:
>
> class Base {
> virtual void func();
>
> }
>
> And I want to do an easy type-equality check based on the vtable-entry
> of func.
>
> Basically, I want to do the following:
>
> bool operator==(const Base& o1, const Base& o2) {
> return &o1.func == &o2.func;
>
> }
>
> How can I do this? I don't want to add any RTTI to the project as it is
> not really needed here (because in my case, it's enough to just compare
> the vtable).
>
> Regards,
> Albert
You can try this:
bool isSameType(const Base& a, const Base& b)
{
return *(void**)&a == *(void**)&b;
}
Which may happen to produce the correct results on your compiler. Even
if it does appear to work, I advise against using it. Use typeid()
instead.
DP
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
compare two objects, if they have the same vtable
On 29 sep, 18:29, Albert Zeyer
> I have an easy base class:
>
> class Base {
> virtual void func();
>
> }
>
> And I want to do an easy type-equality check based on the vtable-entry
> of func.
typeid(obj1) == typeid(obj2).
I don't want to add any RTTI to the project as it is
> not really needed here (because in my case, it's enough to just compare
> the vtable).
RTTI just compares the pointers to the vtable.
The same thing could be written in a non-portable, ugly way, as
*(void**)&obj1 == *(void**)&obj2.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
compare two objects, if they have the same vtable
Erik Wikström schrieb:
> On 2008-09-29 18:29, Albert Zeyer wrote:
>> Hi,
>>
>> I have an easy base class:
>>
>> class Base {
>> virtual void func();
>> }
>>
>> And I want to do an easy type-equality check based on the vtable-entry
>> of func.
>>
>> Basically, I want to do the following:
>>
>> bool operator==(const Base& o1, const Base& o2) {
>> return &o1.func == &o2.func;
>> }
>>
>> How can I do this? I don't want to add any RTTI to the project as it is
>> not really needed here (because in my case, it's enough to just compare
>> the vtable).
>
> bool operator==(const Base& o1, const Base& o2)
> {
> return (typeid(o1) == typeid(o2));
> }
>
> One way if implementing RTTI is to use the an index in the vtable to
> store a pointer to the type_info object for the class. So while it might
> be more efficient to just compare the vtable-pointers themselves the
> difference is very small and you loose portability and readability. By
> the way, if you use any dynamic_cast in your code you already have RTTI
> in your application.
>
I have no RTTI in that application and I also don't want to use RTTI
(for something where it is not needed as the information is there
somewhere...). And that is why dynamic_cast does not work in my application.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Policy-based class design or inheritance?
On 29 sep, 18:29, Vincent
> Hi all,
>
> suppose we can choose between two approaches:
>
> 1) First approach (policy-based class design)
>
> template
> class A {
> ...
>
> public:
> void print() {
> OutputPolicy::print("...");
> }
> };
Alternatively, you can consider this.
template
class A : public OutputPolicy
{
...
};
You could also use CRTP.
> Instinctively I tend toward the first approach. Inheritance is
> undoubtedly a "pillar" of object-oriented programming, but if possible
> I always look for an alternative design.
OOP (inheritance with virtual functions) isn't that good, yes. I
usually avoid it. Especially since C++ often has much better
alternatives.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
compare two objects, if they have the same vtable
> Long answer: you may find it hard to swallow, but C++ has no concept of
> vtable. Moreover the language is intentionally designed so that you
> can't take the address of a member function (you can obtain a
> pointer-to-member-function, but that is *not* an address). So C++ was
> deliberately designed to hide the information you seek.
Can you take an address of a non-member function? I believe you
cannot. What's the logic behind it?
You can approximate the address of the function by looking at the
local stack:
void foo(){
char a;
}
Steps:
1. Figure out whether stack is increasing or decreasing.
2. char is equal to 2 bytes, hence the function's location starts
before (or after that), plus minus off-set
However, as mentioned before, you cannot portably perform these steps.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
SFINAE?
On 29 sep, 20:58, Richard Corden
> courp...@gmail.com wrote:
> > On 24 sep, 21:28, Richard Corden
> >> [...]
>
> [...]
>
> >> 2) For an explicitly specified argument, deduction fails for an array
> >> size that is zero.
>
> >> 14.8.2/2b3b1: Attempting to create an array with an element type that
> >> is void, a function type, or a reference type, or attempting to create
> >> an array with an array size that is zero or negative.
>
> [...]
>
>
>
> > As I said earlier, the second parameter of both function doesn't
> > qualify as a nondeduced context ( check [14.8.2.4/4] ). So there is no
> > deduction failure.
>
> Section 14.8.2 is describing "explicit arguments" that do not need to be
> deduced. The standard clearly states, however, that a problem with
> these arguments results in a "deduction failure".
>
> In other words, deduction failure just means that the function is not
> considered as a viable function for the purpose of overload resolution.
> Although the parameters are not deduced, an invalid argument type may
> still result in a "deduction failure"
>
The problem is that the parameters "char(*)[sizeof(T) - 1]" or
"char[sizeof(T) - 1]" are not governed by the explicit argument
section (14.8.2/2). Those parameters should have followed the same
rules as explicit template arguments because of 14.8.2/4 (the ***as
described above*** part ). However 14.8.2/4 concerns nondeduced
contexts only, and the function parameters above are not nondeduced
contexts (14.8.2.4/4), which is what you missed in your explanation.
Alexandre Courpron.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Goals of perfect Exception Specifiers
Hi all, I am the author of a program called EDoc++ (http://
edoc.sourceforge.net/) that has the goal of trying to alleviate many
problems associated with using exceptions in C++. I am looking to get
a summary of how people do use or would like to use exception
specifiers (assuming they were implemented differently) in C++. I.e.
What in your opinion, are the possible purposes of exception
specifiers (ES) and how do they succeed or fail against those
purposes?
To start with i thought i would summarize the purposes i can think of
for ES:
* Documentation
ES can be used to specify a list of exceptions a given function may
throw so when we use it we can determine if we need to handle those
exceptions or allow them to propagate through our function.
They fail at this currently because ES are not often used (for good
reason). The best we can hope for is manually written documentation
which can be difficult to create and maintain (EDoc++ can already
solve this problem).
* Forced change analysis
If an ES list changes then with static/compile time assertion of ES
(like in Java) we could enforce that functions using it are also
updated, making sure that the author at least thinks about the extra
exception.
Again ES fail at this because they are not asserted at compile time
but at run time (EDoc++ can be used for compile time assertion of ES,
but I honestly do not think ES are a good way to achieve this even
with static checking). It is also arguable if the benefit of this is
worth the maintenance cost. Code between the throw and catch sites
usually just care whether an exception of any type is thrown or not in
order to determine its safety guarantee and does not often care about
the exceptions type. As a result the only places that really care
about the type are the throw and catch sites which are usually a very
small portion of the code base. Having to specify the complete list of
exceptions at every level is tedious and in the case of C++ fraught
with problems.
* Determining exception safety guarantee
Writing code that meets a certain safety guarantee is achieved by
ensuring that certain functions called at certain points do NOT throw
exceptions. Often ES can be used to check that operations do not throw
any exceptions.
Again ES currently fail at this because they are not often used so I
usually refer to documentation instead. Also after initially writing
code that meets say the strong guarantee if things change in the
functions it makes use of it is a difficult/manual task to re-check
the exception safety guarantee. This point in kind-of an amalgamation
of both the documentation and change analysis points above.
* Type restriction
In C++ with templates, a perfect type of exception specification
would allow some restrictions to be placed on template types (Similar
to Concepts but for exception requirements). For example, allowing the
author of a template to require that the template type has a no-throw
destructor (Note I am not advocating use of ES, but rather in a
perfect world this is what I might try and use them to achieve).
Again even with semantics to add such a feature to C++, using an ES as
defining the restriction is dangerous and would not be used in
practice due to the method in which ES are implemented.
The reason for this question is that I have an idea for EDoc++ that
could be used to achieve these same goals without many of the
disadvantages of ES (i.e. A replacement for ES). But i want to gather
the goals of ES from others before I look more into the feasibility of
this.
Thanks,
Brendon.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Policy-based class design or inheritance?
On Sep 29, 2:04 pm, puzzlecracker
> It seems that both approaches need to include A.h file, hence original
> coupling persist. I would use stratagy and passing a pointer (evia
> ctor or setter) to AToStderr class
IMO, there is nothing wrong with including A.h. We should remember
that the whole reason for #include'ing in the first place was to
create the very interdependence that you hope to avoid.
There is beauty and benefit in a certain type of interdependence. It
is the basis of form. If you kill it, the system becomes wobbly, held
together by flimsy ligaments, demanding that the designer remain
perpetually cognizant how things are linked and what treachery might
arise because the designer assumed a role best relegated to a
compiler.
I think it is tragic that some promiment authors have promoted
gettting rid of this interdepence using PIMPL and other techniques
just for sake of faster compilation and other trivial reasons.
[However, there are non-trivial reasons where breaking interdependence
is not only warranted, but necessary.]
> class OutputToStderr {
>
> static void setPrinter(Printer *printer) {
> _printer=printer;
> }
> print();
> private:
> static Printer _printer
> };
Would not a reference be better?
-Le Chaud Lapin-
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
curiously recurring template pattern (CRTP) and types
On Sep 29, 4:52 pm, Alberto Ganesh Barbati
wrote:
> Vidar Hasfjord ha scritto:
> > typedef typename T::X Y; // OK. T is complete here.
>
> Yes, this works fine, but not for the reason you said. T is *not*
> complete *there*.
I wasn't very clear. I guess you take "here" to mean at this point in
the parsing process. I meant that here, inside foo, T will always be
complete at instantiation time. That of course relies on the fact that
foo is being instantiated at the point of use and assumes that Base is
only used for CRTP.
But thanks for elaborating.
Regards,
Vidar Hasfjord
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Templates and forward declarations
On 29 Sep, 18:29, Alberto Ganesh Barbati
wrote:
> Rune Allnor ha scritto:
>
> > On 25 Sep, 23:32, Alberto Ganesh Barbati
> > wrote:
>
> >> So the question is: why do you want to keep both the declaration and
the
> >> implementation in the same file when 99.9% of C++ programmers use two
> >> separate files (except maybe for local/implementation detail classes)?
>
> > Because I don't know any better, I am a C++ autodidact and I am
> > learning as I go. Yechezkel Mett indicated one way of doing things.
> > I would appreciate if somebody could point me to a 'best practice'
> > for how to do these things.
>
> I indicated the best practice in my post:
>
> "Just use separate files and #include the header files you need, when
> you need them."
Which is not a useful answer. I can't imagine that one would need
a declaration without also needing the corresponding implementation.
Which is why my templates are both declared and implemented in the
same file. Once one starts separating the two (as header files) one
need this elaborate orchestration of inlcudes, which makes everything
depend on everything else.
Rune
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]