|
|
|
#1 |
|
Messages: n/a
Hébergeur: |
The following code compiles fine with GCC, Comeau, EDG/C++ and VC++ 8/9:
#include <cstdio> #include <string> int main() { { std::string names[3] = { "One", "Two", "Three" }; } std::puts("\n\npress <ENTER> to exit..."); std::getchar(); return 0; } I think its still invalid; am I right? -- Chris M. Thomasson http://appcore.home.comcast.net |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
Chris Thomasson wrote:
> The following code compiles fine with GCC, Comeau, EDG/C++ and VC++ 8/9: > > > #include <cstdio> > #include <string> > > > int main() { > { > std::string names[3] = { "One", "Two", "Three" }; > } > std::puts("\n\npress <ENTER> to exit..."); > std::getchar(); > return 0; > } > > > I think its still invalid; am I right? I believe you're right that you think it's still invalid (although there is nobody but you that can confirm that so far, there is no way for us to know what you think except when you tell us). However, I don't immediately see anything invalid in the code, could you perhaps elaborate? V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
Victor Bazarov wrote:
> Chris Thomasson wrote: >> The following code compiles fine with GCC, Comeau, EDG/C++ and VC++ 8/9: >> >> >> #include <cstdio> >> #include <string> >> >> >> int main() { >> { >> std::string names[3] = { "One", "Two", "Three" }; >> } >> std::puts("\n\npress <ENTER> to exit..."); >> std::getchar(); >> return 0; >> } >> >> >> I think its still invalid; am I right? > > I believe you're right that you think it's still invalid (although there > is nobody but you that can confirm that so far, there is no way for us > to know what you think except when you tell us). However, I don't > immediately see anything invalid in the code, could you perhaps elaborate? There are lots of things wrong in that code. For starters, it doesn't check that printing to standard output succeeded. (Yes, that was supposed to be humoristic.) |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
"Juha Nieminen" <nospam@thanks.invalid> wrote in message
news:yWg1k.315$oS4.276@read4.inet.fi... > Victor Bazarov wrote: >> Chris Thomasson wrote: >>> The following code compiles fine with GCC, Comeau, EDG/C++ and VC++ 8/9: >>> >>> >>> #include <cstdio> >>> #include <string> >>> >>> >>> int main() { >>> { >>> std::string names[3] = { "One", "Two", "Three" }; >>> } >>> std::puts("\n\npress <ENTER> to exit..."); >>> std::getchar(); >>> return 0; >>> } >>> >>> >>> I think its still invalid; am I right? >> >> I believe you're right that you think it's still invalid (although there >> is nobody but you that can confirm that so far, there is no way for us >> to know what you think except when you tell us). However, I don't >> immediately see anything invalid in the code, could you perhaps >> elaborate? > > There are lots of things wrong in that code. For starters, it doesn't > check that printing to standard output succeeded. > > (Yes, that was supposed to be humoristic.) lol! :^D Okay... Here is what I want to be able to do; the following should compile and run fine: __________________________________________________ _____________________ /* Active Object __________________________________________________ ____________*/ template< typename T, void (T::*T_fp_start) () = &T::start, void (T::*T_fp_join) () = &T::join > struct active { T object; struct guard { T& object; guard(T& _object) : object(_object) { (object.*T_fp_start)(); } ~guard() { (object.*T_fp_join)(); } }; active() { (object.*T_fp_start)(); } template<typename T_p1> active(T_p1& p1) : object(p1) { (object.*T_fp_start)(); } template<typename T_p1> active(T_p1 const& p1) : object(p1) { (object.*T_fp_start)(); } template<typename T_p1, typename T_p2> active(T_p1& p1, T_p2& p2) : object(p1, p2) { (object.*T_fp_start)(); } template<typename T_p1, typename T_p2> active(T_p1 const& p1, T_p2& p2) : object(p1, p2) { (object.*T_fp_start)(); } template<typename T_p1, typename T_p2> active(T_p1& p1, T_p2 const& p2) : object(p1, p2) { (object.*T_fp_start)(); } template<typename T_p1, typename T_p2> active(T_p1 const& p1, T_p2 const& p2) : object(p1, p2) { (object.*T_fp_start)(); } template<typename T_p1, typename T_p2, typename T_p3> active(T_p1 const& p1, T_p2& p2, T_p3& p3) : object(p1, p2, p3) { (object.*T_fp_start)(); } // [and on and on for more and more parameters...] ~active() { (object.*T_fp_join)(); } }; /* Sample usage __________________________________________________ ____________*/ #include <cstdio> #include <cstddef> #include <string> struct Buffer { Buffer() { std::printf("(%p)->Buffer::Buffer()\n", (void*)this); } ~Buffer() { std::printf("(%p)->Buffer::~Buffer()\n", (void*)this); } }; struct Producer { int const m_id; std::string const m_name; Buffer& m_Buffer; Producer(int const id, Buffer& _Buffer) : m_id(id), m_name("Default Producer"), m_Buffer(_Buffer) { std::printf("(%p)->Producer::Producer()\n", (void*)this); } Producer(int const id, char const* name, Buffer& _Buffer) : m_id(id), m_name(name), m_Buffer(_Buffer) { std::printf("(%p)->Producer::Producer()\n", (void*)this); } ~Producer() { std::printf("(%p)->Producer::~Producer()\n", (void*)this); } void start() { std::printf("(%p)-> void Producer<'%s'>::start() - Buffer(%p)\n", (void*)this, m_name.c_str(), (void*)&m_Buffer); } void join() { std::printf("(%p)-> void Producer::join() - Buffer(%p)\n", (void*)this, (void*)&m_Buffer); } }; struct Consumer { int const m_id; std::string const m_name; Buffer& m_Buffer; Consumer(int const id, Buffer& _Buffer) : m_id(id), m_name("Default Consumer"), m_Buffer(_Buffer) { std::printf("(%p)->Consumer::Consumer()\n", (void*)this); } Consumer(int const id, char const* name, Buffer& _Buffer) : m_id(id), m_name(name), m_Buffer(_Buffer) { std::printf("(%p)->Consumer::Consumer()\n", (void*)this); } ~Consumer() { std::printf("(%p)->Consumer::~Consumer()\n", (void*)this); } void start() { std::printf("(%p)-> void Consumer<'%s'>::start() - Buffer(%p)\n", (void*)this, m_name.c_str(), (void*)&m_Buffer); } void join() { std::printf("(%p)-> void Consumer::join() - Buffer(%p)\n", (void*)this, (void*)&m_Buffer); } }; #define ARRAY_DEPTH(mp_this) ( \ sizeof((mp_this)) / sizeof((mp_this)[0]) \ ) int main() { { Buffer b; active<Producer> p[] = { active<Producer>(123, b), active<Producer>(456, "Custom Producer", b), active<Producer>(789, b), active<Producer>(234, "I am a Producer!", b), active<Producer>(567, b) }; active<Consumer> c[] = { active<Consumer>(891, "I am a Consumer!", b), active<Consumer>(345, b), active<Consumer>(678, b) }; std::size_t i; std::puts("-----------------------"); for (i = 0; i < ARRAY_DEPTH(p); ++i) { std::printf("p[%u].m_id == %d\n", i, p[i].object.m_id); std::printf("p[%u].m_name == %s\n----\n", i, p[i].object.m_name.c_str()); } putchar('\n'); for (i = 0; i < ARRAY_DEPTH(c); ++i) { std::printf("c[%u].m_id == %d\n", i, c[i].object.m_id); std::printf("c[%u].m_name == %s\n----\n", i, c[i].object.m_name.c_str()); } std::puts("-----------------------"); } std::puts("\n\npress <ENTER> to exit..."); std::getchar(); return 0; } __________________________________________________ _____________________ This code compiles perfectly fine with no warnings on GCC, Comeau, VC++ 8/9 and EDG/C++. Can any of you spot any undefined behavior? Also, is the code anywhere near standard C++? Please try and bear with be here. I am NOT a C++ expert... :^( Thanks for all of your time! I really do appreciate it. |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
"Victor Bazarov" <v.Abazarov@comAcast.net> wrote in message
news:g2402s$9mn$1@news.datemas.de... > Chris Thomasson wrote: >> The following code compiles fine with GCC, Comeau, EDG/C++ and VC++ 8/9: >> >> >> #include <cstdio> >> #include <string> >> >> >> int main() { >> { >> std::string names[3] = { "One", "Two", "Three" }; >> } >> std::puts("\n\npress <ENTER> to exit..."); >> std::getchar(); >> return 0; >> } >> >> >> I think its still invalid; am I right? > > I believe you're right that you think it's still invalid (although there > is nobody but you that can confirm that so far, there is no way for us to > know what you think except when you tell us). However, I don't > immediately see anything invalid in the code, could you perhaps elaborate? I was thinking that the compiler would complain about something like: "this form of non-aggregate initialization requires a unary constructor" For some reason I thought I would have to do something like: #include <cstdio> #include <string> int main() { { std::string names[3] = { std::string("One"), std::string("Two"), std::string("Three") }; } std::puts("\n\npress <ENTER> to exit..."); std::getchar(); return 0; } This just goes to show you how little I actually know about C++! I am a C guy. Ouch! Anyway, here is my next question: http://groups.google.com/group/comp....4f85b6d588eaf7 Does the code in that post look Kosher? |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
"Chris Thomasson" <cristom@comcast.net> wrote in message
news:34CdnS4u3Kw1ANjVnZ2dnUVZ_h_inZ2d@comcast.com. .. [...] > Okay... Here is what I want to be able to do; the following should compile > and run fine: > __________________________________________________ _____________________ > /* Active Object > __________________________________________________ ____________*/ > template< > typename T, > void (T::*T_fp_start) () = &T::start, > void (T::*T_fp_join) () = &T::join >> struct active { [...] I think that there might be some problems with ambiguity in the active<T> template constructors for certain usages. Need to think some more on this aspect... Humm... > }; > [...] |
|
|
|
#7 |
|
Messages: n/a
Hébergeur: |
Chris Thomasson wrote:
> [..] > Okay... Here is what I want to be able to do; the following should > compile and run fine: > __________________________________________________ _____________________ > /* Active Object > __________________________________________________ ____________*/ > template< > typename T, > void (T::*T_fp_start) () = &T::start, > void (T::*T_fp_join) () = &T::join > struct active { > > T object; > > struct guard { > T& object; > > guard(T& _object) : object(_object) { > (object.*T_fp_start)(); > } > > ~guard() { > (object.*T_fp_join)(); > } > }; I don't understand the importance of this 'guard' struct here. > > active() { > (object.*T_fp_start)(); > } This is rather dangerous. If 'object' is a POD, it is left uninitialised. If you wanted it default-initilaised, you need to put it in the initialiser list: active() : object() { ... } otherwise you're trying to call a member function that might want to access the object's data, which are not in the proper state... > > [..] > }; > > > > > /* Sample usage > __________________________________________________ ____________*/ > #include <cstdio> > #include <cstddef> > #include <string> > > struct Buffer { > Buffer() { > std::printf("(%p)->Buffer::Buffer()\n", (void*)this); > } > > ~Buffer() { > std::printf("(%p)->Buffer::~Buffer()\n", (void*)this); > } > }; > > > struct Producer { > int const m_id; > std::string const m_name; > Buffer& m_Buffer; > > Producer(int const id, Buffer& _Buffer) The name "_Buffer" is reserved by the implementation for any uses, so you cannot use it here. I recommend using lower case ('_buffer') or renaming the argument altogether. All names that begin with an underscore and a capital letter are reserved. Same sentiment applies for all occurrences of "_Buffer" below. > : m_id(id), m_name("Default Producer"), m_Buffer(_Buffer) { > std::printf("(%p)->Producer::Producer()\n", (void*)this); I don't believe you need to cast 'this' here. > } > > Producer(int const id, char const* name, Buffer& _Buffer) > : m_id(id), m_name(name), m_Buffer(_Buffer) { > std::printf("(%p)->Producer::Producer()\n", (void*)this); > } > > ~Producer() { > std::printf("(%p)->Producer::~Producer()\n", (void*)this); > } > > void start() { > std::printf("(%p)-> void Producer<'%s'>::start() - Buffer(%p)\n", > (void*)this, m_name.c_str(), (void*)&m_Buffer); > } > > void join() { > std::printf("(%p)-> void Producer::join() - Buffer(%p)\n", > (void*)this, (void*)&m_Buffer); > } > }; > > > struct Consumer { > int const m_id; > std::string const m_name; > Buffer& m_Buffer; > > Consumer(int const id, Buffer& _Buffer) > : m_id(id), m_name("Default Consumer"), m_Buffer(_Buffer) { > std::printf("(%p)->Consumer::Consumer()\n", (void*)this); > } > > Consumer(int const id, char const* name, Buffer& _Buffer) > : m_id(id), m_name(name), m_Buffer(_Buffer) { > std::printf("(%p)->Consumer::Consumer()\n", (void*)this); > } > > ~Consumer() { > std::printf("(%p)->Consumer::~Consumer()\n", (void*)this); > } > > void start() { > std::printf("(%p)-> void Consumer<'%s'>::start() - Buffer(%p)\n", > (void*)this, m_name.c_str(), (void*)&m_Buffer); > } > > void join() { > std::printf("(%p)-> void Consumer::join() - Buffer(%p)\n", > (void*)this, (void*)&m_Buffer); > } > }; > > > #define ARRAY_DEPTH(mp_this) ( \ > sizeof((mp_this)) / sizeof((mp_this)[0]) \ > ) You're better off not using a macro for this. Try template<class T, size_t depth> size_t array_depth(T (&mp_this)[depth]) { return depth; } (the case has changed, this is not a macro any more). > > > int main() { > { > Buffer b; > > active<Producer> p[] = { > active<Producer>(123, b), > active<Producer>(456, "Custom Producer", b), > active<Producer>(789, b), > active<Producer>(234, "I am a Producer!", b), > active<Producer>(567, b) > }; > > active<Consumer> c[] = { > active<Consumer>(891, "I am a Consumer!", b), > active<Consumer>(345, b), > active<Consumer>(678, b) > }; > > std::size_t i; > > std::puts("-----------------------"); > > for (i = 0; i < ARRAY_DEPTH(p); ++i) { > std::printf("p[%u].m_id == %d\n", i, p[i].object.m_id); > std::printf("p[%u].m_name == %s\n----\n", > i, p[i].object.m_name.c_str()); > } > > putchar('\n'); > > for (i = 0; i < ARRAY_DEPTH(c); ++i) { > std::printf("c[%u].m_id == %d\n", i, c[i].object.m_id); > std::printf("c[%u].m_name == %s\n----\n", > i, c[i].object.m_name.c_str()); > } > > std::puts("-----------------------"); > } > std::puts("\n\npress <ENTER> to exit..."); > std::getchar(); > return 0; > } > > __________________________________________________ _____________________ > > > > This code compiles perfectly fine with no warnings on GCC, Comeau, VC++ > 8/9 and EDG/C++. So, they are a bit forgiving when it comes to reserved names (and you got lucky), and you didn't use the default c-tor for your 'active' template instantiated on a POD... > Can any of you spot any undefined behavior? Also, is the code anywhere > near standard C++? Please try and bear with be here. I am NOT a C++ > expert... Well, the code's close. V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask |
|
|
|
#8 |
|
Messages: n/a
Hébergeur: |
"Chris Thomasson" <cristom@comcast.net> wrote in message
news:kOudnR5GhJgGPdjVnZ2dnUVZ_o_inZ2d@comcast.com. .. > "Chris Thomasson" <cristom@comcast.net> wrote in message > news:34CdnS4u3Kw1ANjVnZ2dnUVZ_h_inZ2d@comcast.com. .. > [...] >> Okay... Here is what I want to be able to do; the following should >> compile and run fine: >> __________________________________________________ _____________________ >> /* Active Object >> __________________________________________________ ____________*/ >> template< >> typename T, >> void (T::*T_fp_start) () = &T::start, >> void (T::*T_fp_join) () = &T::join >>> struct active { > [...] > > > I think that there might be some problems with ambiguity in the active<T> > template constructors for certain usages. Need to think some more on this > aspect... Humm... Well, AFAICT the ambiguity problem only exists because I explicitly defined the template constructor types as references! Here is a fixed version which uses no decorations on the template parameter types passed into the constructor: template< typename T, void (T::*T_fp_start) () = &T::start, void (T::*T_fp_join) () = &T::join > struct active { T object; struct guard { T& object; guard(T& _object) : object(_object) { (object.*T_fp_start)(); } ~guard() { (object.*T_fp_join)(); } }; active() { (object.*T_fp_start)(); } template<typename T_p1> active(T_p1 p1) : object(p1) { (object.*T_fp_start)(); } template<typename T_p1, typename T_p2> active(T_p1 p1, T_p2 p2) : object(p1, p2) { (object.*T_fp_start)(); } template<typename T_p1, typename T_p2, typename T_p3> active(T_p1 p1, T_p2 p2, T_p3 p3) : object(p1, p2, p3) { (object.*T_fp_start)(); } template<typename T_p1, typename T_p2, typename T_p3, typename T_p4> active(T_p1 p1, T_p2 p2, T_p3 p3, T_p4 p4) : object(p1, p2, p3, p4) { (object.*T_fp_start)(); } // [and on and on for more and more parameters...] ~active() { (object.*T_fp_join)(); } }; |
|
|
|
#9 |
|
Messages: n/a
Hébergeur: |
"Chris Thomasson" <cristom@comcast.net> wrote in message
news dWdnR35AOULPtjVnZ2dnUVZ_tninZ2d@comcast.com. ..> "Chris Thomasson" <cristom@comcast.net> wrote in message > news:kOudnR5GhJgGPdjVnZ2dnUVZ_o_inZ2d@comcast.com. .. >> "Chris Thomasson" <cristom@comcast.net> wrote in message >> news:34CdnS4u3Kw1ANjVnZ2dnUVZ_h_inZ2d@comcast.com. .. >> [...] >>> Okay... Here is what I want to be able to do; the following should >>> compile and run fine: >>> __________________________________________________ _____________________ >>> /* Active Object >>> __________________________________________________ ____________*/ >>> template< >>> typename T, >>> void (T::*T_fp_start) () = &T::start, >>> void (T::*T_fp_join) () = &T::join >>>> struct active { >> [...] >> >> >> I think that there might be some problems with ambiguity in the active<T> >> template constructors for certain usages. Need to think some more on this >> aspect... Humm... > > Well, AFAICT the ambiguity problem only exists because I explicitly > defined the template constructor types as references! Here is a fixed > version which uses no decorations on the template parameter types passed > into the constructor: > > > template< > typename T, > void (T::*T_fp_start) () = &T::start, > void (T::*T_fp_join) () = &T::join >> struct active { > > T object; [...] > active() { > (object.*T_fp_start)(); > } Need to fix the error: active() : object() { (object.*T_fp_start)(); } [...] |
|
|
|
#10 |
|
Messages: n/a
Hébergeur: |
"Victor Bazarov" <v.Abazarov@comAcast.net> wrote in message
news:g24801$pek$1@news.datemas.de... > Chris Thomasson wrote: >> [..] >> Okay... Here is what I want to be able to do; the following should >> compile and run fine: >> __________________________________________________ _____________________ >> /* Active Object >> __________________________________________________ ____________*/ >> template< >> typename T, >> void (T::*T_fp_start) () = &T::start, >> void (T::*T_fp_join) () = &T::join > struct active { >> >> T object; >> >> struct guard { >> T& object; >> >> guard(T& _object) : object(_object) { >> (object.*T_fp_start)(); >> } >> >> ~guard() { >> (object.*T_fp_join)(); >> } >> }; > > I don't understand the importance of this 'guard' struct here. Well, its there so the user can so something like: { object o; active<object>::guard g(o); } So they can intervene in between the object construction and the invocation of its start procedure. > >> >> active() { >> (object.*T_fp_start)(); >> } > > This is rather dangerous. If 'object' is a POD, it is left uninitialised. > If you wanted it default-initilaised, you need to put it in the > initialiser list: > > active() : object() { > ... > } > > otherwise you're trying to call a member function that might want to > access the object's data, which are not in the proper state... OUCH!! :^O [...] >> Producer(int const id, Buffer& _Buffer) > > The name "_Buffer" is reserved by the implementation for any uses, so you > cannot use it here. I recommend using lower case ('_buffer') or renaming > the argument altogether. All names that begin with an underscore and a > capital letter are reserved. > > Same sentiment applies for all occurrences of "_Buffer" below. DOH! Thanks again. What a bone headed mistake. :^(... >> : m_id(id), m_name("Default Producer"), m_Buffer(_Buffer) { >> std::printf("(%p)->Producer::Producer()\n", (void*)this); > > I don't believe you need to cast 'this' here. Well, I thought that you could only pass a void* pointer to represent a %p formatter. [...] >> >> >> #define ARRAY_DEPTH(mp_this) ( \ >> sizeof((mp_this)) / sizeof((mp_this)[0]) \ >> ) > > You're better off not using a macro for this. Try > > template<class T, size_t depth> > size_t array_depth(T (&mp_this)[depth]) { > return depth; > } > > (the case has changed, this is not a macro any more). Indeed. The macro is ugly compared to the template. [...] >> This code compiles perfectly fine with no warnings on GCC, Comeau, VC++ >> 8/9 and EDG/C++. > > So, they are a bit forgiving when it comes to reserved names (and you got > lucky), and you didn't use the default c-tor for your 'active' template > instantiated on a POD... Very lucky! ;^D >> Can any of you spot any undefined behavior? Also, is the code anywhere >> near standard C++? Please try and bear with be here. I am NOT a C++ >> expert... > > Well, the code's close. With all of your excellent , I think I am going to get this right after all! I will repost the code in full once I kill all the bugs you so kindly pointed out: - Default construct the `active<T>: bject' in the `active<T>::active' ctor.- Honor the reserved namespace rules by eliminating leading underscore and capital from all the names. - Remove the macros in favor of templates. Also, I think I need to remove the explicit reference decorations to the templated active<T> constructors. In other words I need to change: template<typename T_p1> active(T_p1& p1) : object(p1) { (object.*T_fp_start)(); } to: template<typename T_p1> active(T_p1 p1) : object(p1) { (object.*T_fp_start)(); } This should elude some ambiguity problems I can foresee with the former definition... |
|
|
|
#11 |
|
Messages: n/a
Hébergeur: |
Chris Thomasson wrote:
> [..] I think I need to remove the explicit reference decorations to the > templated active<T> constructors. In other words I need to change: > > template<typename T_p1> > active(T_p1& p1) : object(p1) { > (object.*T_fp_start)(); > } > > > to: > > > template<typename T_p1> > active(T_p1 p1) : object(p1) { > (object.*T_fp_start)(); > } > > > This should elude some ambiguity problems I can foresee with the former > definition... Those usually work better, yes. V -- Please remove capital 'A's when replying by e-mail I do not respond to top-posted replies, please don't ask |
|
|
|
#12 |
|
Messages: n/a
Hébergeur: |
"Victor Bazarov" <v.Abazarov@comAcast.net> wrote in message
news:g24930$qv3$2@news.datemas.de... > Chris Thomasson wrote: >> [..] I think I need to remove the explicit reference decorations to the >> templated active<T> constructors. In other words I need to change: >> >> template<typename T_p1> >> active(T_p1& p1) : object(p1) { >> (object.*T_fp_start)(); >> } >> >> >> to: >> >> >> template<typename T_p1> >> active(T_p1 p1) : object(p1) { >> (object.*T_fp_start)(); >> } >> >> >> This should elude some ambiguity problems I can foresee with the former >> definition... > > Those usually work better, yes. Okay good; I thought so. BTW, the main end goal of this `active<T>' template is going to be an attempt at a full-blown C++ layer over POSIX Threads. I was thinking of using it to start and join objects which derive from a threading base class, which will provide the start/join() procedures for `active<T>' to automatically invoke, in a manner which respects the RAII idiom. Also, for the syntactic sugar of starting threads. You should be able to so something like: class object : public thread_base { void on_entry() { // [the thread function]; } }; int main() { { active<object> o[4]; } return 0; } That looks fairly clean to me... ;^) |
|
|
|
#13 |
|
Messages: n/a
Hébergeur: |
On Jun 3, 4:18 pm, "Chris Thomasson" <cris...@comcast.net> wrote:
> "Victor Bazarov" <v.Abaza...@comAcast.net> wrote in message > > Chris Thomasson wrote: > >> : m_id(id), m_name("Default Producer"), m_Buffer(_Buffer) { > >> std::printf("(%p)->Producer::Producer()\n", (void*)this); > > > I don't believe you need to cast 'this' here. > > Well, I thought that you could only pass a void* pointer to represent a %p > formatter. You can pass any data pointer, it's all the same. However, GCC's handy printf() warnings also warn when you pass a non-void* to a %p, so casting it does get rid of that warning. Other than squashing a compiler warning you don't have to do the cast. |
|
|
|
#14 |
|
Messages: n/a
Hébergeur: |
Chris Thomasson wrote:
> I was thinking that the compiler would complain about something like: > > "this form of non-aggregate initialization requires a unary constructor" > > For some reason I thought I would have to do something like: > > > #include <cstdio> > #include <string> > > > int main() { > { > std::string names[3] = { > std::string("One"), > std::string("Two"), > std::string("Three") > }; > } > std::puts("\n\npress <ENTER> to exit..."); > std::getchar(); > return 0; > } std::string's char* constructor is not explicit. You are actually using the constructor when you pass char const* data into your array construction. |
|
|
|
#15 |
|
Messages: n/a
Hébergeur: |
<jason.cipriani@gmail.com> wrote in message
news:f7ce3d34-671d-48c4-acc0-6f8450be44f1@r66g2000hsg.googlegroups.com... > On Jun 3, 4:18 pm, "Chris Thomasson" <cris...@comcast.net> wrote: >> "Victor Bazarov" <v.Abaza...@comAcast.net> wrote in message >> > Chris Thomasson wrote: >> >> : m_id(id), m_name("Default Producer"), m_Buffer(_Buffer) { >> >> std::printf("(%p)->Producer::Producer()\n", (void*)this); >> >> > I don't believe you need to cast 'this' here. >> >> Well, I thought that you could only pass a void* pointer to represent a >> %p >> formatter. > > You can pass any data pointer, it's all the same. Even a function pointer? > However, GCC's handy > printf() warnings also warn when you pass a non-void* to a %p, so > casting it does get rid of that warning. Other than squashing a > compiler warning you don't have to do the cast. |
|
|
|
#16 |
|
Messages: n/a
Hébergeur: |
On Jun 3, 8:09 pm, "Chris Thomasson" <cris...@comcast.net> wrote:
> <jason.cipri...@gmail.com> wrote in message > > You can pass any data pointer, it's all the same. > > Even a function pointer? Nope (not reliably, anyways). That's why I specified *data* pointer. :-) |
|
|
|
#17 |
|
Messages: n/a
Hébergeur: |
<jason.cipriani@gmail.com> wrote in message
news:e5fee407-6d6b-454e-9fbc-f9255992f0d3@56g2000hsm.googlegroups.com... > On Jun 3, 8:09 pm, "Chris Thomasson" <cris...@comcast.net> wrote: >> <jason.cipri...@gmail.com> wrote in message >> > You can pass any data pointer, it's all the same. >> >> Even a function pointer? > > Nope (not reliably, anyways). That's why I specified *data* > pointer. :-) I misinterpreted you. :^o |
|
|
|
#18 |
|
Messages: n/a
Hébergeur: |
On Jun 3, 10:02 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> Chris Thomasson wrote: [...] > > : m_id(id), m_name("Default Producer"), m_Buffer(_Buffer) { > > std::printf("(%p)->Producer::Producer()\n", (void*)this); > I don't believe you need to cast 'this' here. He's outputting to a "%p" format, which requires a void* (or void const*). He's passing this as a vararg. This doesn't have type void*. So without the cast, it's undefined behavior. This sort of thing is why good programmers eschew printf and company. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
|
|
#19 |
|
Messages: n/a
Hébergeur: |
On Jun 4, 1:36 am, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.com> wrote: > On Jun 3, 4:18 pm, "Chris Thomasson" <cris...@comcast.net> wrote: > > "Victor Bazarov" <v.Abaza...@comAcast.net> wrote in message > > > Chris Thomasson wrote: > > >> : m_id(id), m_name("Default Producer"), m_Buffer(_Buffer) { > > >> std::printf("(%p)->Producer::Producer()\n", (void*)this); > > > I don't believe you need to cast 'this' here. > > Well, I thought that you could only pass a void* pointer to > > represent a %p formatter. > You can pass any data pointer, it's all the same. That is simply false. Technically, you can only pass a void*; I don't see anything in ISO/IEC 9899 which would even allow void const*. In practice, unless the implementation explicitly verifies, you'll also be able to pass char* and char const*, since they are required to have the same size and representation as a void*. Anything else is undefined behavior, and I've worked on machines where it would cause random junk to be output (and could even cause a core dump if there were also a %s or a %f elsewhere in the format string). > However, GCC's handy printf() warnings also warn when you pass > a non-void* to a %p, so casting it does get rid of that > warning. Other than squashing a compiler warning you don't > have to do the cast. According to the C standard, you do. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
|
|
#20 |
|
Messages: n/a
Hébergeur: |
James Kanze wrote:
> On Jun 4, 1:36 am, "jason.cipri...@gmail.com" > <jason.cipri...@gmail.com> wrote: > > You can pass any data pointer, it's all the same. > > That is simply false. Technically, you can only pass a void*; I > don't see anything in ISO/IEC 9899 which would even allow void > const*. In practice, unless the implementation explicitly > verifies, you'll also be able to pass char* and char const*, > since they are required to have the same size and representation > as a void*. Anything else is undefined behavior, and ... I did not know that. Is that to say that these two statements are not the same: int i; int *k = &i; void *a = *(void **)&k; // <--- this void *b = (void *)k; // <--- and this Or does that only mean that fprintf with %p is undefined unless you explicitly cast pointer parameters to (void *) first? I could've sworn that somewhere in C++ it said that the representation for data pointers was always the same -- do you know where the relevant part of the standard is (looking in C++03, I couldn't find anything relevant). > ...I've > worked on machines where it would cause random junk to be > output ... Just out of curiosity, what machines cause things like printf("%p", (int *)&something); to print random junk? Jason |
|
|
|
#21 |
|
Messages: n/a
Hébergeur: |
On Jun 4, 5:16 am, James Kanze <james.ka...@gmail.com> wrote:
> This sort of thing is why good programmers eschew printf and > company. Do you happen to know if C++0x is introducing a convenient ostream interface that makes things like: printf("%+9.4f %8.3f\n", value1, value2); Slightly easier to deal with than: cout << showpos << fixed << setw(9) << setprecision(4) << value1 << noshowpos << setw(8) << setprecision(3) << value2 << endl; Do you also happen to know if C++0x is introducing an iostreams interface with informative error returns, e.g an equivalent of: string errmsg; if (fprintf(...) < 0) errmsg = strerror(errno); // <-- ? I find iostreams has little to no value over stdio when you are only dealing with built-in scalar types. Of course it's convenient to define new ostream << operators for complex types; but for this kind of stuff iostreams is incredibly cumbersome... Jason |
|
|
|
#22 |
|
Messages: n/a
Hébergeur: |
On Jun 4, 5:43 pm, "jason.cipri...@gmail.com" <jason.cipri...@gmail.com> wrote: > James Kanze wrote: > > On Jun 4, 1:36 am, "jason.cipri...@gmail.com" > > <jason.cipri...@gmail.com> wrote: > > > You can pass any data pointer, it's all the same. > > That is simply false. Technically, you can only pass a void*; I > > don't see anything in ISO/IEC 9899 which would even allow void > > const*. In practice, unless the implementation explicitly > > verifies, you'll also be able to pass char* and char const*, > > since they are required to have the same size and representation > > as a void*. Anything else is undefined behavior, and ... > I did not know that. Is that to say that these two statements > are not the same: > int i; > int *k = &i; > void *a = *(void **)&k; // <--- this > void *b = (void *)k; // <--- and this Certainly not. The first is undefined behavior, and will result in a more or less random value for a on some processors. > Or does that only mean that fprintf with %p is undefined > unless you explicitly cast pointer parameters to (void *) > first? Correct. > I could've sworn that somewhere in C++ it said that the > representation for data pointers was always the same -- do you > know where the relevant part of the standard is (looking in > C++03, I couldn't find anything relevant). I'm not sure I understand. You want me to point out in the standard where the guarantee isn't given. The real question is the reverse: what makes you think that an int* has the same size and layout as a void*. The fact that the standard feels it necessary to offer some limited guarantees should be a strong indication, however (from §3.9.2, paragraphs 3 and 4, from the 1998 version, since that and the current draft are all I have on line here): [...] The value representation of pointer types is implementation-defined. Pointers to cv-qualified and cv-unqualified version of layout-compatible types shall have the same value representation and alignment requirements. Objects of cv-qualified or cv-unqualified type void* (pointer to void) can be used to point to objects of unknown type. A void* shall be able to hold any object pointer. A cv-qualified or cv-unqualified void* shall have the same representation and alignment requiremns as a cv-qualified or cv-unqualified char*. In other words: const and non-const pointers to the same type (or a layout compatible type) must have the same representation, and void* and char* must have the same representation. In addition, the way incomplete types can be used more or less forces an implementation to use the same representation for all pointers to class types. (The only thing the representation could depend on is the spelling of the class name, which is, of course, ridiculous.) You might also look at the guarantees concerning casts---it's quite clear that casting a void* to int* and back is not guaranteed to result in the original pointer. That's there for a reason. > > ...I've worked on machines where it would cause random junk > > to be output ... > Just out of curiosity, what machines cause things like > printf("%p&q |