2

I am trying to write a class Core, it's member variable is a pointer. The copy constructor is Core(Core& x) instead of Core(const Core& x).

Core has a member function Core Core::new_core (int * ptr), the code has a problem when I try to construct Core new_core= core.new_core(ptr);, please see the code and error information below.

#include<iostream>

class Core
{
    private:
    int* a;

    public:
    Core(int* in) {a=in;}
    Core(Core& x) {a = x.data();}

    inline const int * data() const {return a;}
    inline       int * data()       {return a;}

    Core new_core (int * ptr)
    {
        Core b(ptr);
        return b;
    }
};

using namespace std;

int main()
{
    int ptr[3]= {1,2,3};
    Core core(ptr);
    Core new_core= core.new_core(ptr);
    cout<< new_core.data() <<endl;
    return 0; 
}

Error information:

main.cpp: In function ‘int main()’:

main.cpp:30:37: error: no matching function for call to ‘Core::Core(Core)’

Core new_core= core.new_core(ptr);
                                 ^

main.cpp:30:37: note: candidates are:

main.cpp:12:6: note: Core::Core(Core&)

 Core(Core& x) { a = x.data() ;}
 ^

main.cpp:12:6: note: no known conversion for argument 1 from ‘Core’ to >‘Core&’

main.cpp:10:6: note: Core::Core(int*)

 Core(int* in) {a=in;}
 ^

main.cpp:10:6: note: no known conversion for argument 1 from ‘Core’ to ‘int*’

I can easily fix the problem by replacing

Core(Core& x) { a = x.data() ;}

to

Core(const Core& x) { a = const_cast<int* > ( x.data() ) ;}, 

is there a better way to solve the problem without using const_cast?

I want to keep int* a private, and keep following two lines:

inline const int * data() const {return a;}
inline       int * data()       {return a;}

Thank you.

Hao Shi
  • 503
  • 4
  • 16
  • It really depends on what you want this class to do. Given that it is only referencing external data, does it make sense for `int * data() ` not to be `const`? i.e. `int * data() const;`. – juanchopanza Jul 11 '16 at 19:33
  • Thank you, juanchopanza. I am make a too general example. In my real application, Core is a derived class, const int * data() const is from base class, which I can not change. I guess I have to use Core(const Core& x) to solve the problem? – Hao Shi Jul 11 '16 at 19:44
  • Your problem is that a non-const rvalue reference cannot bind to a temporary. But an rvalue reference can. There was an answer (now deleted) that was almost right... – juanchopanza Jul 11 '16 at 19:47
  • By the way, If I use: `Core core_a(ptr);` `Core core_b( core_a);`, the code will works fine. Why I can not use `Core new_core( core.new_core(ptr) );` ? – Hao Shi Jul 11 '16 at 19:48
  • I see, thanks a lot. – Hao Shi Jul 11 '16 at 19:53

1 Answers1

4

The problem here is that new_core returns a Core which is a temporary. When you use it in

Core new_core= core.new_core(ptr);

The compiler calls the copy constructor but it cannot bind to that temporary since it takes a reference. To fix this we can change the copy constructor to take a const Core& which can bind to the temporary and allow you to make a copy.

In this example to get around the const and the use ofconst_cast we can access the class member directly like:

Core(const Core& x) : a(x.a) {}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • Thanks a lot, this really help. I have one more question, in my real example, Core is a template drived class, and `int * a` is in template based class. When I need to access `a`, I always need to use `this->a`, it looks like I can not use: `Core(const Core& x) : this->a(x.a) {}`. – Hao Shi Jul 11 '16 at 20:07
  • @HaoShi This sounds like the base class needs to have a proper copy constructor. If you could provide a [mcve] in your question I may be able to help you further. – NathanOliver Jul 11 '16 at 20:09
  • Thanks NathanOliver! I see, I can solve the problem by writing a proper copy constructor in base class. – Hao Shi Jul 11 '16 at 20:12