Thread: Implicit conversion problem

  1. #1
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654

    Implicit conversion problem

    Ah, this one is a little tough nut to crack, it seems...
    Here's how the code should be, but which doesn't work:

    Code:
    Stuff::AddTrayIcon( _T(""), _T(""), _T("Countdown active!"), 0, 1000, new Callback(this, &CCountdownApp::TrayRightClick) );
    Callback is a typedef:
    Code:
    typedef Stuff::CClassCallback<CCountdownApp*, void (CCountdownApp::*)()> Callback;
    And AddTrayIcon is declared as:
    Code:
    void AddTrayIcon(const CString& strToolTip, const CString& strBalloonTip, const CString& strBalloonTitle, HICON hIcon, UINT nTimeOut, CTrayCallbacks Callbacks);
    CTrayCallbacks has a constructor which takes a pointer to a CCallback class:
    Code:
    CTrayCallbacks(pp<CCallback> pCRButtonUp);
    CClassCallback inherits from CCallback:
    Code:
    template<typename Class, typename Function> class CClassCallback: public CCallback
    pp is a define for the memory manager class which has an overload for pointer type T*:
    Code:
    CMemoryManager(T* pNew);
    So what should happen is that I create a new CClassCallback, which is implicitly cast to CCallback, which in turn is accepted by the CTrayCallbacks constructor.
    Now, the above code doesn't seem to work.
    However, this does:

    Code:
    Stuff::CCallback* pTest = new Callback(this, &CCountdownApp::TrayRightClick);
    Stuff::CTrayCallbacks Test2(pTest);
    ...And this doesn't work:
    Code:
    Stuff::AddTrayIcon( _T(""), _T(""), _T("Countdown active!"), 0, 1000, pTest );
    Which is basically the same as the Test2 line, is it not? This is why I'm confused as to why the implicit conversions won't take place when I pass the object directly to the function. I can pass Test2 perfectly fine.
    This one also works fine:
    Code:
    Stuff::AddTrayIcon( _T(""), _T(""), _T("Countdown active!"), 0, 1000, (Stuff::CTrayCallbacks)pTest );
    Ideas?
    Last edited by Elysia; 03-02-2008 at 10:06 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    There are two user-defined implicit conversions involved in the line you want. First, the user-defined conversion from CClassCallback* to CMemoryManager<CCallback>, via CMemoryManager's conversion constructor. Second, the user-defined conversion from CMemoryManager<CCallback> to CTrayCallbacks, via CTrayCallback's conversion constructor.

    However, the rules of C++ dictate that in any implicit conversion chain, only one user-defined conversion may be present. This basically prevents the compiler from "going wild" and using an absurdly long sequence of user-defined conversions to compile some code that should never have compiled.

    In this case, it's a non-problem, though, because you're already violating a different rule: never mix an RAII initialization line with any other code. The correct code to use is
    Code:
    pp<CCallback> ptr(new CClassCallback(...));
    AddTrayIcon(..., ptr);
    The reasoning is thus: there is no guaranteed order for the statements in a long line. Your long line contains:
    - A new operation, which allocates and initializes a CClassCallback.
    - Implicit creation of a CMemoryManager temporary.
    - Implicit creation of a CString temporary for strBalloonTitle.
    - Implicit creation of a CString temporary for strBalloonTip.
    - Implicit creation of a CString temporary for strToolTip.

    Among the allowed operation sequences the compiler may choose is:
    1) A new operation, which allocates and initializes a CClassCallback.
    2) Implicit creation of a CString temporary for strBalloonTitle.
    3) Implicit creation of a CString temporary for strBalloonTip.
    4) Implicit creation of a CString temporary for strToolTip.
    5) Implicit creation of a CMemoryManager temporary.

    The interesting thing here is that RAII kicks in only after the CMemoryManager is fully constructed. This means that if any of the CString creations fail (and they could, on out-of-memory), you will leak the CClassCallback.

    Thus, the rule is that resource allocation and initialization are written in such a way that they cannot be separated by other operations. The creation of an RAII object and its initialization with a newly allocated resource are put on the same line, alone.

    Once you've done that, you've split the two user-defined conversions up anyway and the original problem goes away.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Very interesting.
    So the point is that after the creation of CClassCallback, there is no guarantee that the memory manager object will be constructed and thus, if the CStrings would fail, the new memory would be lost?
    But OTOH, if I do the RAII on a separate line, it will guarantee that the memory manager object will be constructed and can get rid of the allocated memory is anything throws.

    Ohoho. Must remember this
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Bin packing problem....
    By 81N4RY_DR460N in forum C++ Programming
    Replies: 0
    Last Post: 08-01-2005, 05:20 AM
  2. implicit conversion not working
    By Mr_Jack in forum C++ Programming
    Replies: 4
    Last Post: 03-09-2004, 10:50 AM
  3. implicit conversion
    By cj56 in forum C++ Programming
    Replies: 2
    Last Post: 05-26-2003, 11:36 AM
  4. Configurations give different results
    By Hubas in forum Windows Programming
    Replies: 2
    Last Post: 04-11-2003, 11:43 AM
  5. Replies: 2
    Last Post: 02-07-2002, 09:39 AM