Link to home
Start Free TrialLog in
Avatar of phoffric
phoffric

asked on

c++11 Understanding errors re: make_shared, emplace_back, and push_back

Trying out syntax for C++11 sometimes falling into rabbit holes. This program works with a lot of trial and error. But, if I uncomment either of two lines, I get errors. I would appreciate it if someone could help me interpret the errors.
#include <iostream>
#include <vector>
#include <memory>
using namespace std;

class Base_t {
public:
   virtual ~Base_t() {}
   virtual int foo(int x) const = 0;
};

class derived1_t : public Base_t {
public:
   ~derived1_t() {}
   int foo(int x) const override {
      return 1111 + x;
   }
};

class derived2_t : public Base_t {
public:
   ~derived2_t() {}
   int foo(int x) const override {
      return 2222 + x;
   }
};

using container_t = vector<shared_ptr<Base_t>>;

int main() {
   container_t cont;
   Base_t* d1 = new derived1_t();
   Base_t* d2 = new derived2_t();
//    cont.push_back(d1);
//    cont.push_back(make_shared<Base_t>(new derived2_t()));
   cont.emplace_back(d1);
   cont.emplace_back(new derived2_t());
   cont.emplace_back(new derived1_t());
   cont.emplace_back(d2);

   int ii = 0;
   for (auto elem : cont) { cout << elem->foo(++ii) << endl; }
}

Open in new window

If I uncomment out line 34: cont.push_back(d1);, then I get these errors:
1>    \emplace_back_and_make_shared.cpp(34): error C2664: 'void std::vector<std::shared_ptr<Base_t>,std::allocator<_Ty>>::push_back(_Ty &&)': cannot convert argument 1 from 'Base_t *' to 'const _Ty &'
1>            with
1>            [
1>                _Ty=std::shared_ptr<Base_t>
1>            ]
1>    \emplace_back_and_make_shared.cpp(33): note: Reason: cannot convert from 'Base_t *' to 'const _Ty'
1>            with
1>            [
1>                _Ty=std::shared_ptr<Base_t>
1>            ]
1>    \emplace_back_and_make_shared.cpp(34): note: Constructor for class 'std::shared_ptr<Base_t>' is declared 'explicit'
1>    1 Error

Open in new window

ideone gives this error:
prog.cpp:34:22: error: no matching function for call to ‘std::vector<std::shared_ptr<Base_t> >::push_back(Base_t*&)’
     cont.push_back(d1);
                      ^

Open in new window

Now, if line 34 is commented, but line 35 is uncommented, then there are 2 errors:
cont.push_back(make_shared<Base_t>(new derived2_t()));
1>    c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1799): error C2259: 'Base_t': cannot instantiate abstract class
1>    c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1799): note: due to following members:
1>    c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1799): note: 'int Base_t::foo(int) const': is abstract
1>    \emplace_back_and_make_shared.cpp(9): note: see declaration of 'Base_t::foo'
1>    c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1865): note: see reference to function template instantiation 'std::_Ref_count_obj<_Ty>::_Ref_count_obj<derived2_t*>(derived2_t *&&)' being compiled
1>            with
1>            [
1>                _Ty=Base_t
1>            ]
1>    c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1866): note: see reference to function template instantiation 'std::_Ref_count_obj<_Ty>::_Ref_count_obj<derived2_t*>(derived2_t *&&)' being compiled
1>            with
1>            [
1>                _Ty=Base_t
1>            ]
1>    \emplace_back_and_make_shared.cpp(35): note: see reference to function template instantiation 'std::shared_ptr<Base_t> std::make_shared<Base_t,derived2_t*>(derived2_t *&&)' being compiled
1>    c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1801): error C2664: 'Base_t::Base_t(const Base_t &)': cannot convert argument 1 from '_Ty' to 'const Base_t &'
1>            with
1>            [
1>                _Ty=derived2_t *
1>            ]
1>    c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1799): note: Reason: cannot convert from '_Ty' to 'const Base_t'
1>            with
1>            [
1>                _Ty=derived2_t *
1>            ]
1>    c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1799): note: No constructor could take the source type, or constructor overload resolution was ambiguous
1>
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1799): error C2259: 'Base_t': cannot instantiate abstract class
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\memory(1801): error C2664: 'Base_t::Base_t(const Base_t &)': cannot convert argument 1 from '_Ty' to 'const Base_t &'
1>    0 Warning(s)
1>    2 Error(s)

Open in new window

Why does the line 34 push_back(d1) fail, but the line 36 emplace_back(d1) works?
What is the proper way to use push_back instead of emplace_back for this program?
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

The first error is because shared_ptr has an explicit constructor. I suspect it works with emplace because that is taking the pointer and passing it to sharrd_ptr constructor to create a new in place item, whereas push_back is trying to create a temporary from the argument, but can't due to the explicit constructor.

The second error is, I think, because you're using make_shared wrong. Try...

make_shared<Derived2_t>()

If I had to guess, I'd say it looks like you used to explicitly construct a shared_ptr and changed it to make_shared, but not properly.

I'm on my phone, so this is untested.
ASKER CERTIFIED SOLUTION
Avatar of Zoppo
Zoppo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
What Zoppo said :)

Unfortunately, being on my phone, I was unable to be that detailed. Nice explaination, Zoppo.
Thanks :o)
Avatar of phoffric
phoffric

ASKER

>> The first error is because shared_ptr has an explicit constructor.
I looked and saw that now. Thanks. I guess the error "Constructor for class 'std::shared_ptr<Base_t>' is declared 'explicit'" should have clued me in a little more; but still lost in trying to interpret the rest of the error message.

Thank you Zoppo for your detailed explanation. This example was a little tricky. I think I am beginning to understand the problems I was having. I need to try variations on just one C++11 feature at a time, and then maybe mixing them together won't be such a mess.

>>  you have to use derived2_t-specialization of std::make_shared, i.e.:
cont.push_back(std::make_shared<derived2_t>());
I wasn't sure what you meant by specialization. (I usually think of template <> for specializations. Is this what you are referring to?)
Also, could you please show the flow through the templates of how this line is compiled correctly.

Here is the program that produces the correct output, but upon exit, it crashes with an access error shown below.
#include <iostream>
#include <memory>
#include <vector>
#include <string>
using namespace std;

class test
{
   std::string m_text;
   int m_number = 0;

public:
   test(std::string text, int number)
      : m_text{ text }
      , m_number{ number }
   {}
};


class Base_t {
public:
   virtual ~Base_t() {}
   virtual int foo(int x) const = 0;
};

class derived1_t : public Base_t {
public:
   ~derived1_t() {}
   int foo(int x) const override {
      return 1111 + x;
   }
};

class derived2_t : public Base_t {
public:
   ~derived2_t() {}
   int foo(int x) const override {
      return 2222 + x;
   }
};

using container_t = vector<shared_ptr<Base_t>>;

int main() {
   std::vector<test> data;    // Method 1 (recommended)
   data.emplace_back("Text", 123);

   test t("Method 2", 456);                    // Method 2 (boo his)
   data.emplace_back(t);


   container_t cont;
   Base_t* d1 = new derived1_t();
   Base_t* d2 = new derived2_t();
   cont.push_back(std::shared_ptr<Base_t>{d1} );
   cont.push_back( make_shared<derived2_t>() );
// cont.push_back(make_shared<derived2_t>(new derived2_t()));
   cont.emplace_back(d1);
   cont.emplace_back(new derived2_t());
   cont.emplace_back(new derived1_t());
   cont.emplace_back(d2);

   int ii = 0;
   for (auto elem : cont) { cout << elem->foo(++ii) << endl; }
}

Open in new window

In VS 2017, upon exiting the program, I get this popup when Line 55 is uncommented:
: 0xC0000005: Access violation reading location 0xDDDDDDDD.

memory header:
private:
	virtual void _Destroy() noexcept override
		{	// destroy managed resource
		delete _Ptr;  XXX
		}

Open in new window

BTW - I have no particular deadline to get a better understanding of this question. So, no rush.
I'd like to thank both of you in helping me get familiarized with C++11.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks again.