Thread: Gcc can't find obvious copy constructor

  1. #1
    Registered User
    Join Date
    Apr 2007
    Posts
    141

    Gcc can't find obvious copy constructor

    Here is another lovely example of some code that MS vis studio compiles and runs correctly but that gcc can't compile and just chokes.


    Code:
    /* templated matrix class */
    template<typename ftype>
    class dynmatrix {
    protected:
    int issub ;
    public:
    int nrows ;
    int ncols ;
    
    /* default constructor and copy constructor and assignment operator are
    all defined or overloaded */
    
    /* copy constructor */
    dynmatrix(dynmatrix &rhs)
    {
    
    /* blah blah */
    }
    
    dynmatrix &operator=(const dynmatrix &rhs)
    {
    /* assignment operator checks for empty left hand side and 
       generates new matrix if necessary,  otherwise copies */
    }
    
    
    /* construct from a file */
    /* constructor that reads directly from a file */
    dynmatrix(const char *fname)
    {
    issub = 0 ;
    read(fname) ;
    }
    
    /* function template inside a templated class  avoid this unless you like using
    the arcane keywords typename and template in your declarations */
    /* conversion copy between float and double flat dynmatrix */
    template <typename etype>
    dynmatrix<etype> dcopy()
    {
    
    /* copies to a new, possibly different elementyped matrix */
    }
    } ;  // end dynmatrix
    
    int main(int argc, char *argv[])
    {
    /* construct a float matrix and fill it with data from somewhere else (  c ) */
    dynmatrix<float> dm(c) ;
    
    /*  the next two lines compile and work in gcc,  but only because the assignment
    operator can deal with the empty dd */
    dynmatrix<double> dd ;
    dd = dm.dcopy<double>() ;
    
    /* the next line is supposed to create d2 via a copy constructor.  it wont compile 
    with gcc.  However MS Vis studio compiles it and it works correctly */
    dynmatrix<double> d2 = dm.copy<double>() ;
    
    }
    Gcc 4.3 is too stupid to find the obvious copy constructor. It gives this error:
    MatrixTest.cpp:261: error: no matching function for call to â
    matrix.h:1958: note: candidates are: cudamat::dynmatrix<ftype>::dynmatrix(const char*) [with ftype = double]
    matrix.h:1823: note: cudamat::dynmatrix<ftype>::dynmatrix(cudamat::dynm atrix<ftype>&) [with ftype = double]

    Note the highly informative inclusion of spurious characters as well. The second candidate looks like a match to me....

    I grow weary of the supposedly strict standards conformant gcc. I'm not sure I much like strict C++ if it takes half a day to dig through each C++ syntax quirk.

  2. #2
    Resu Deretsiger Nightowl's Avatar
    Join Date
    Nov 2008
    Location
    /dev/null
    Posts
    186
    . . . I'd say that it's MSVC that's messing up, not GCC. MSVC isn't exactly the most standards-compliant complier around.

    MatrixTest.cpp:261: error: no matching function for call to â
    Can you clarify on this, please? Is G++ messing up, or is it your copying?

    EDIT: Actually, let me clarify. MSVC is a lot more forgiving, less strict than GCC/G++ is. I like the strict mode, but I suppose it's not for everyone.
    Do as I say, not as I do . . .

    Experimentation is the essence of programming. Just remember to make a backup first.

    "I'm a firm believer that <SomeGod> gave us two ears and one mouth for a reason - we are supposed to listen, twice as much as we talk." - LEAF

    Questions posted by these guidelines are more likely to be answered.

    Debian GNU/Linux user, with the awesome window manager, the git version control system, and the cmake buildsystem generator.

  3. #3
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by SevenThunders View Post
    Here is another lovely example of some code that MS vis studio compiles and runs correctly but that gcc can't compile and just chokes.

    Code:
    /* copy constructor */
    dynmatrix(dynmatrix &rhs)
    {
    
    /* blah blah */
    }
    That's a constructor alright, but not a copy-constructor. A copy-constructor must take the parameter by const-refercnce.
    Turn the warning level of Visual Studio up to 4 and you'll probably get some kind of warning about a non-standard extension used where you try and use it.
    Last edited by iMalc; 03-19-2009 at 12:09 AM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  4. #4
    Resu Deretsiger Nightowl's Avatar
    Join Date
    Nov 2008
    Location
    /dev/null
    Posts
    186
    Good call, iMalc. Completely missed that.

    SevenThunders got it here, however . . .
    Code:
    dynmatrix &operator=(const dynmatrix &rhs)
    {
    /* assignment operator checks for empty left hand side and 
       generates new matrix if necessary,  otherwise copies */
    }
    Looks like [s]he just missed that one.

    No need to blame your compiler, it's usually your fault . . . (/me knows from experience, including a week-long hunt to reproduce a compiler "bug" that turned out to be my own cursed fault.)
    Do as I say, not as I do . . .

    Experimentation is the essence of programming. Just remember to make a backup first.

    "I'm a firm believer that <SomeGod> gave us two ears and one mouth for a reason - we are supposed to listen, twice as much as we talk." - LEAF

    Questions posted by these guidelines are more likely to be answered.

    Debian GNU/Linux user, with the awesome window manager, the git version control system, and the cmake buildsystem generator.

  5. #5
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by iMalc View Post
    That's a constructor alright, but not a copy-constructor. A copy-constructor must take the parameter by const-refercnce.
    Not true. A copy constructor is one that accepts a reference to an object of the type being created. There is no requirement that it accept a const-reference.

    However, the copy constructor that accepts a const reference is required if you intend to pass the return value from a function, because [roughly speaking] a temporary - which must hold the return value from dcopy() function in this example - cannot be passed to a function expecting a non-const reference.

    In any event, for the original question, VC++ was at fault because it accepted your code. gcc was correct.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  6. #6
    The larch
    Join Date
    May 2006
    Posts
    3,573
    In general case, VC++ accepts temporary objects for non-const reference parameters as a non-standard extension.

    Code:
    #include <iostream>
    #include <string>
    
    void foo(std::string& s) //accepts string by non-const reference
    {
        std::cout << s << '\n';
    }
    
    int main()
    {
        foo(std::string("hello world")); //call with a temporary
    }
    Compiles with VC++, not with GCC.

    Make the parameter const and it will be correct C++ (temporaries can be bound to const references which prolong the life-time of the temporary, but not to non-const references).
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Add the /Za compiler switch in MSVC (Disable language extensions), and it will fail too.
    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

  8. #8
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Thanks a bunch guys. You saved me some hours of grief here. How do you keep track of these wretched details?

    However, the copy constructor that accepts a const reference is required if you intend to pass the return value from a function, because [roughly speaking] a temporary - which must hold the return value from dcopy() function in this example - cannot be passed to a function expecting a non-const reference.
    grumpy is that specified by the standard or is there some logic to this? I thought if you pass a return value (not by reference) that it creates a copy for you. Thus the temporary is destroyed within the function scope (dcopy() in this case), but the return value is a copy in the callers scope. Why do you need const?

    In fact I have been assuming that a decent compiler, on optimization, will optimize away the extra copy. I'm not sure I follow the logic behind the const requirement.

    Oh and the spurious a hat character is being generated by gcc 4.3. I should create a simple example and file it as a bug I suppose.
    Last edited by SevenThunders; 03-19-2009 at 12:43 PM.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by SevenThunders
    I thought if you pass a return value (not by reference) that it creates a copy for you. Thus the temporary is destroyed within the function scope (dcopy() in this case), but the return value is a copy in the callers scope. Why do you need const?
    The return value is a temporary, and it is to be copied to construct d2, hence the copy constructor is invoked.

    Quote Originally Posted by SevenThunders
    In fact I have been assuming that a decent compiler, on optimization, will optimize away the extra copy. I'm not sure I follow the logic behind the const requirement.
    Yes, and it can do so even in the presence of side effects. The problem here is that it cannot even do so because according to the copy constructor's signature, it cannot invoke the copy constructor.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I'm not sure I follow the logic behind the const requirement.
    The requirement has nothing to do with performance or strict correctness. The fact is that non-const reference parameters should only be used where there is the intention of modifying the argument. With a temporary, such modifications would not be visible when the function returns. Thus, passing a temporary to a function expecting a non-const reference is most likely unintentional and the wrong thing to do. The C++ standard committee thought this sufficient reason to forbid binding non-const references to temporaries. MS thought differently, and later got caught in compatibility concerns.
    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

  11. #11
    Registered User
    Join Date
    Apr 2007
    Posts
    141
    Quote Originally Posted by CornedBee View Post
    The requirement has nothing to do with performance or strict correctness. The fact is that non-const reference parameters should only be used where there is the intention of modifying the argument. With a temporary, such modifications would not be visible when the function returns. Thus, passing a temporary to a function expecting a non-const reference is most likely unintentional and the wrong thing to do. The C++ standard committee thought this sufficient reason to forbid binding non-const references to temporaries. MS thought differently, and later got caught in compatibility concerns.
    OK I can see the logic of that. My only problem is that when I adhere by this I seem to get a lot errors from MS Visual studio with regards to passing non constant parameters into the arguments. I end up doing const casts and the const keyword starts to spread like a virus.

    When I have time I'll try to generate a case of this.

  12. #12
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by grumpy View Post
    Not true. A copy constructor is one that accepts a reference to an object of the type being created. There is no requirement that it accept a const-reference.
    Oh duh, auto_ptr *smacks forehead*.

    I think I got mixed up with the fact that a templated constructor is not a copy-constructor.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  13. #13
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    the const keyword starts to spread like a virus.
    It's supposed to. A good maxim to adhere to in new code is, "things are const until proven otherwise".

    In old, non-const-correct code, trying to introduce const can be frustrating. Starting with copy constructors would be a good idea, though. Non-const copy constructors are a blight.
    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

  14. #14
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by SevenThunders View Post
    grumpy is that specified by the standard or is there some logic to this?
    Well ..... both actually. It's specified by the standard, and there is some logic to it.
    Quote Originally Posted by SevenThunders View Post
    I thought if you pass a return value (not by reference) that it creates a copy for you. Thus the temporary is destroyed within the function scope (dcopy() in this case), but the return value is a copy in the callers scope. Why do you need const?
    The logic is that a function that accepts non-const reference may change the object referred to. If that object is a temporary, those changes are undetectable once control returns to the caller, so need not be done. While, yes, it is possible to argue "why not do the the changes anyway?", in practice such things more often represent a mistake in the calling code.
    Quote Originally Posted by SevenThunders View Post
    In fact I have been assuming that a decent compiler, on optimization, will optimize away the extra copy. I'm not sure I follow the logic behind the const requirement.
    The compiler is required by the standard to diagnose the code in the same way, whether it performs the optimisation or not. That is necessary because the compiler diagnostics need to be independent of compiler optimisation settings. It would break the intent of the standard if you could develop code that fails with a non-optimising compiler (eg when debugging) but passes an optimising compiler. The portability concerns concerns of that would be enormous.

    The fact that Microsoft attempted to push some other specific interpretations into the standard, and failed, does not change that.

    In this case, that means the compiler is required to act as if the temporary is required, and therefore diagnose the need for the const-reference copy constructor. Once it has done that, it is allowed to eliminate the temporary from existence in some circumstances. The specific circumstances are if it can be shown the only way of detecting the existence of the temporary is by tracking constructor and destructor calls.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pointer conversion problems with a copy constructor
    By stanlvw in forum C++ Programming
    Replies: 8
    Last Post: 01-14-2008, 12:06 AM
  2. Copy constructor for Queue ADT (as an Array)
    By clegs in forum C++ Programming
    Replies: 2
    Last Post: 11-28-2007, 11:05 PM
  3. Replies: 2
    Last Post: 04-04-2007, 06:34 PM
  4. Can't find my constructor
    By Nippashish in forum C++ Programming
    Replies: 4
    Last Post: 12-06-2002, 08:17 PM
  5. copy constructor
    By Eber Kain in forum C++ Programming
    Replies: 1
    Last Post: 09-30-2002, 05:03 PM