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.
cont.push_back(make_shared <Base_t>(n ew derived2_t()));
What is the proper way to use push_back instead of emplace_back for this program?
#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; }
}
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
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);
^
Now, if line 34 is commented, but line 35 is uncommented, then there are 2 errors:cont.push_back(make_shared
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)
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?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
What Zoppo said :)
Unfortunately, being on my phone, I was unable to be that detailed. Nice explaination, Zoppo.
Unfortunately, being on my phone, I was unable to be that detailed. Nice explaination, Zoppo.
Thanks :o)
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.:
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.
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_s hared<deri ved2_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; }
}
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
}
BTW - I have no particular deadline to get a better understanding of this question. So, no rush.
ASKER
I'd like to thank both of you in helping me get familiarized with C++11.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks again.
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.