Which line calls the default constructor? - c++

Previous SO post consulted: Default Constructor Calls
Here is the code:
#include <iostream>
#include <unordered_map>
using namespace std;
struct item {
std::string name;
int price;
// item() = default;
item(std::string n, int p): name(n), price(p) {}
};
void createItems(std::unordered_map<std::string, item>& blah);
int main()
{
std::unordered_map<std::string, item> blah;
createItems(blah);
cout << blah["armor"].name << " " << blah["armor"].price << std::endl;
return 0;
}
void createItems(std::unordered_map<std::string, item>& blah) {
item i1{"armor", 1000};
item i2{"amulet", 200};
blah["armor"] = i1;
blah["amulet"] = i2;
return;
}
The error message when run:
main.cpp:20:25: required from here
/usr/include/c++/11/tuple:1824:9: error: no matching function for call to ‘item::item()’
1824 | second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:10:5: note: candidate: ‘item::item(std::string, int)’
10 | item(std::string n, int p): name(n), price(p) {}
| ^~~~
main.cpp:10:5: note: candidate expects 2 arguments, 0 provided
main.cpp:6:8: note: candidate: ‘item::item(const item&)’
6 | struct item {
| ^~~~
main.cpp:6:8: note: candidate expects 1 argument, 0 provided
main.cpp:6:8: note: candidate: ‘item::item(item&&)’
main.cpp:6:8: note: candidate expects 1 argument, 0 provided
From my understanding, the default constructor is called but since I commented the line out the call results in an error.
Question: Why (and where) is the default constructor needed? My suspicion is that blah["armor"] calls the default constructor, but why?

As tkausl hinted at in their comment, the index operator is what needs the default constructor.
What the index operator does is
find tree location for key
if this location does not exist
create location
copy-construct key there
default-construct value there
return reference to value at location
Step 5 needs the default constructor. And since everything needs to be resolved at compile time, it needs the default constructor even if you never actually use a non-existent key. (You do, though.)
If you don't have a default constructor, you can't use the index operator. Use insert, emplace or try_emplace add elements to the map, and find or at to look them up.

Related

C++ compiler error: use of deleted function std::variant()

I am continually getting the following error message telling me that I am using a deleted function, which I think is the std::variant default constructor.
In file included from main.cpp:2:
Document.hpp: In instantiation of ‘Document<StateVariant, EventVariant, Transitions>::Document(StateVariant&&) [with StateVariant = std::variant<DraftState, PublishState>; EventVariant = std::variant<EventWrite, EventRead>; Transitions = TransitionRegister]’:
main.cpp:7:61: required from here
Document.hpp:33:37: error: use of deleted function ‘std::variant<_Types>::variant() [with _Types = {DraftState, PublishState}]’
33 | Document(StateVariant &&a_state) {
| ^
In file included from Document.hpp:6,
from main.cpp:2:
/usr/include/c++/11/variant:1385:7: note: ‘std::variant<_Types>::variant() [with _Types = {DraftState, PublishState}]’ is implicitly deleted because the default definition would be ill-formed:
1385 | variant() = default;
| ^~~~~~~
/usr/include/c++/11/variant:1385:7: error: use of deleted function ‘constexpr std::_Enable_default_constructor<false, _Tag>::_Enable_default_constructor() [with _Tag = std::variant<DraftState, PublishState>]’
In file included from /usr/include/c++/11/variant:38,
from Document.hpp:6,
from main.cpp:2:
/usr/include/c++/11/bits/enable_special_members.h:112:15: note: declared here
112 | constexpr _Enable_default_constructor() noexcept = delete;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
The code is roughly:
#include <iostream>
#include <variant>
class DraftState {
public:
DraftState() = default; // default constructor
DraftState(const DraftState &a_state) { m_msg = a_state.m_msg; } // copy constructor
DraftState(const std::string &a_rMsg = "") { m_msg = a_rMsg; } // custom constructor
DraftState(DraftState &&a_state) { m_msg = std::move(a_state.m_msg);} // move constructor
DraftState& operator=(DraftState &&a_state) { if(this != &a_state) { m_msg = std::move(a_state.m_msg); } return *this; } // move assignable constructor
~DraftState() = default; // destructor
std::string getState() { return "DraftState"; }
std::string m_msg;
};
class PublishState{
// similar to DraftState
};
using State = std::variant<DraftState, PublishState>;
template<typename StateVariant>
class Document
{
public:
Document() = default;
Document(StateVariant &&a_state) {
m_state = std::move(a_state);
}
StateVariant m_state;
//...
};
int main()
{
DraftState draftState("draft");
Document<State> doc(draftState);
return 0;
}
I have tried adding a default constructor call in the custom constructor Document(StateVariant &&a_state)'s initializer list but that does not seem to work either. Any help understanding this cryptic message is appreciated thanks. Sorry for the long code.
While you do need to work on a minimal example, the core problem is your DraftState default constructor is ambiguous with your string constructor with a default argument. See https://godbolt.org/z/hTnsjoWaW
To be default constructible, std::variant requires the first type argument to be default constructible. The ambiguity causes the compiler to think your class is not default constructible, and therefore neither is the variant.
Also, your move constructor for Document should use the member initializer list, rather than assignment. And your DraftState is missing the copy assignment operator, though unless there's more to it, I wouldn't explicitly define all of the copy/move/destructor values. See the Rule of Five.

Variable initialized with garbage value in copy constructor

In my comp sci class we are making a vector class. I am stuck because my copy constructor is initializing my 'limit' variable with a garbage value and I dont understand why.
Here is my main:
myStringVector v1 {"a", "b", "c"};
std::cout << "make it here?" << std::endl;
myStringVector v2 = v1;
std::cout << v1[0] << v1[1] << v1[2] << std::endl;
std::cout << v2[0] << v2[1] << v2[2] << std::endl;
assert(v1 == v2);
std::cout << "Passed copy ctor" << std::endl;
Here is the constructor that takes an initializer_list
myStringVector::myStringVector(std::initializer_list<myString> list){
this->reserve(list.size());
for(int i = 0; i < limit-1; i++){
construct(first+i, list.begin()[i]);
}
}
Here is the copy constructor
myStringVector::myStringVector(const myStringVector& data){
reserve((data.limit)-1);
for(int i = 0; i < data.limit-1; i++){
construct(&first+i, data.first+i);
}
}
Here is what reserve looks like
void myStringVector::reserve(int n){
this->first = allocate<myString>(n);
this->last = first+n;
this->limit = n+1;
}
My assertion in main is failing because I overloaded the == operator to first check if the limits are equal. If they are not, the function returns false. The function continues after that, but it is failing the assertion because I am getting my v1 to be 4, which is correct, and then my v2 is some large number that doesn't make sense.
I've tried rewriting my copy constructor to directly initialize the members of the class without using reserve and it still doesn't work. It is still assigning garbage values to limit. The rest of it is working fine.
Here is what main is outputting...
make it here?
abc
abc
4 7500072
Assertion failed: v1 == v2, file myCodeTres.cpp, line 58
I feel like I've tried everything I can think of to try and fix this but nothings working. Any advice for me?
Thanks.
Update: these are the compiler error I get when I leave the ampersand out.
In file included from myCodeTres.cpp:20:
myMemory.hpp: In instantiation of 'T* construct(T*, Args&& ...) [with T = myString; Args = {myString*}]':
myStringVector.cpp:25:36: required from here
myMemory.hpp:61:10: error: no matching function for call to 'myString::myString(myString*)'
61 | return new (p) T(std::forward(args)...);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**then there are some weird errors that are in blue on the compiler screen **
In file included from myCodeTres.cpp:23:
myString.cpp:42:1: note: candidate: 'myString::myString(myString&&)'
42 | myString::myString(myString&& move) : strLength(strlen(move.stringVar)) //move constructor to move contents from
| ^~~~~~~~
myString.cpp:42:31: note: no known conversion for argument 1 from 'myString*' to 'myString&&'
42 | myString::myString(myString&& move) : strLength(strlen(move.stringVar)) //move constructor to move contents from
| ~~~~~~~~~~~^~~~
myString.cpp:32:1: note: candidate: 'myString::myString(const myString&)'
32 | myString::myString(const myString& strToCpy) : strLength(strlen(strToCpy.stringVar)) //copy constructor that removes old elements
| ^~~~~~~~
myString.cpp:32:36: note: no known conversion for argument 1 from 'myString*' to 'const myString&'
32 | myString::myString(const myString& strToCpy) : strLength(strlen(strToCpy.stringVar)) //copy constructor that removes old elements
| ~~~~~~~~~~~~~~~~^~~~~~~~
In file included from myCodeTres.cpp:23:
myString.cpp:23:1: note: candidate: 'myString::myString(const char*, std::size_t)'
23 | myString::myString(const char* cPnt, std::size_t size) : strLength(size) //constructor to take a size and const ptr to char
| ^~~~~~~~
myString.cpp:23:1: note: candidate expects 2 arguments, 1 provided
myString.cpp:14:1: note: candidate: 'myString::myString(const char*)'
14 | myString::myString(const char* cPnt) : strLength(strlen(cPnt)) //constructor to initialize to a given const ptr to char.
| ^~~~~~~~
myString.cpp:14:32: note: no known conversion for argument 1 from 'myString*' to 'const char*'
14 | myString::myString(const char* cPnt) : strLength(strlen(cPnt)) //constructor to initialize to a given const ptr to char.
| ~~~~~~~~~~~~^~~~
myString.cpp:8:1: note: candidate: 'myString::myString()'
8 | myString::myString() //default constructor: initializes empty string.
| ^~~~~~~~
myString.cpp:8:1: note: candidate expects 0 arguments, 1 provided
update: whole class definition
#ifndef MYSTRINGVECTOR_HPP
#define MYSTRINGVECTOR_HPP
#include "myString.hpp"
#include <initializer_list>
class myStringVector{
private:
myString *first, *last;
int limit = 0;
public:
void reserve(int); //allocate memory at 'first' for n myString's
myStringVector(); //call to reserve(0)
myStringVector(std::initializer_list<myString>);
myStringVector(const myStringVector&);
bool empty();
bool operator==(const myStringVector&);
myString operator[](int);
int getSize() const;
};
#endif //MYSTRINGVECTOR_HPP_INCLUDED
.cpp file
#include "myStringVector.hpp"
#include "myMemory.hpp"
#include <initializer_list>
void myStringVector::reserve(int n){
this->first = allocate<myString>(n);
this->last = first+n;
this->limit = n+1;
}
myStringVector::myStringVector(){
this->reserve(0);
}
myStringVector::myStringVector(std::initializer_list<myString> list){
this->reserve(list.size());
for(int i = 0; i < limit-1; i++){
construct(first+i, list.begin()[i]);
}
}
myStringVector::myStringVector(const myStringVector& data){
reserve((data.limit)-1);
for(int i = 0; i < data.limit-1; i++){
construct(first+i, data.first+i);
}
}
bool myStringVector::empty(){
return (limit-1 == 0);
}
bool myStringVector::operator==(const myStringVector& data){
std::cout << limit << " " << data.limit << std::endl;
if(this->limit != data.limit)
return 0;
for(int i = 0; i < limit; i++){
if(*(first+i) != *(data.first+i))
return 0;
}
return 1;
}
myString myStringVector::operator[](int index){
return *(first+index);
}
int myStringVector::getSize() const{
return limit-1;
}
formatting is a bit off because uploading code to stackoverflow is tedious as can be.
Simple error, in your copy constructor
construct(&first+i, data.first+i);
should be
construct(first+i, data.first+i);
EDIT
This from the initializer list constructor works.
construct(first+i, list.begin()[i]);
Now think carefully about the types here. The first argument is simple enough, it's a pointer to myString i.e. myString*. The second is a little more complicated because you have to understand std::initializer_list but if you follow it through it's a const reference to myString, i.e. const myString&. Now this is fine because construct is defined like this
template <class T>
void construct(T* first, const T& second);
i.e. for some type T it's first argument is a pointer to that type, and it's second argument is a const reference to that type.
Now look at the types for the second use of construct (the one that doesn't compile)
construct(first+i, data.first+i);
The first argument is myString* and the second argument is const myString*. Two pointers! This is why it doesn't compile! Your solution was to add an extra pointer to the first argument. The types of
construct(&first+i, data.first+i);
are myString** and const myString*. That compiles because you have a double pointer on the left and a single pointer on the right but it means that you are constructing pointers to myString not myString objects, and that is not what you want.
What you should have done is remove the pointer from the second argument, not add an extra pointer to the first argument. In other words the correct code is this
construct(first+i, data.first[i]);
Now the types are myString* for the first and const myString& for the second argument. Exactly the same as in the other constructor.
Try that change and let me know how it goes.

Unable to store classes inside my template Linked List [duplicate]

I'm writing a C++ application in which I have a Controller class with two nested structs, defined in my header file as follows:
class Controller {
struct help_message { // controller.hpp, line 19
std::string summary;
std::string details;
help_message(const std::string&, const std::string&);
};
struct player_command {
cmd_t cmd;
help_message help;
// cmd_t is my own typedef, irrelevant for this question
player_command(const cmd_t&, const help_message&);
};
// more members...
};
In my source file, I have this:
Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h) {
cmd = c;
help = h;
};
Controller::help_message::help_message(const std::string& s, const std::string& d) {
summary = s;
details = d;
};
which I thought was fine, but when I compile, this is what I get (controller.cpp line 12 is the first line of the source snippet above):
g++ -g -Wall -std=c++0x -c -o controller.o controller.cpp
controller.cpp: In constructor ‘palla::Controller::player_command::player_command(void (palla::Controller::* const&)(const args_t&), const palla::Controller::help_message&)’:
controller.cpp:12:93: error: no matching function for call to ‘palla::Controller::help_message::help_message()’
controller.cpp:12:93: note: candidates are:
In file included from controller.cpp:7:0:
controller.hpp:22:3: note: palla::Controller::help_message::help_message(const string&, const string&)
controller.hpp:22:3: note: candidate expects 2 arguments, 0 provided
controller.hpp:19:9: note: palla::Controller::help_message::help_message(const palla::Controller::help_message&)
controller.hpp:19:9: note: candidate expects 1 argument, 0 provided
controller.hpp:19:9: note: palla::Controller::help_message::help_message(palla::Controller::help_message&&)
controller.hpp:19:9: note: candidate expects 1 argument, 0 provided
make: *** [controller.o] Error 1
From what I can deduce, the compiler is somewhere trying to call the default constructor of help_message, which doesn't exist. It then tries to match the call up with the constructor I created as well as with the generated copy-constructor and assignment operator, and failing each on the number of arguments.
But what part of my code is calling a default constructor? And how do I fix this error?
The player_command() constructor first default constructs help and then assigns to it:
Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h) {
cmd = c;
help = h;
};
Change that to:
Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h)
: cmd(c),
help(h)
{
};
See Benefits of Initialization lists
The player_command struct contains a help_message (help), and there is no default constructor for help_message. When the player_command constructor is called, by default the help member variable will be default constructed. You are immediately assigning help to the given parameter but this will be after it is default constructed. Instead change the constructor to be something like:
Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h) : cmd(c), help(h)
{}
This will invoke the copy constructor for both cmd and help member variables instead of doing default construction and then assignment.
You are not using the syntax which avoids the copy constructor. The argument is passed by reference (no copy constructor) but it is indeed copied when assigned to the ivar.
Class::Class(const Variable &var) {
this->var = var; // assignment here, this invokes copy contructor!
}
You should use the following syntax:
Class::Class(const Variable &var) : var(var) { }

C++ code does not compile

The code does not compile. I do not understand what the error is, help please)
#include <iostream>
#include <fstream>
class Record{
std::string product_name;
std::string product_category;
int price;
int amount;
public:
Record(std::string newName, std::string newCategory, int newPrice, int newAmount){
product_name=newName;
product_category=newCategory;
price=newPrice;
amount=newAmount;
}
std::string getName(){
return product_name;
}
std::string getCategory(){
return product_category;
}
int getPrice(){
return price;
}
int getAmount(){
return amount;
}
void setName(std::string newName){
product_name=newName;
}
void setCategory(std::string newCategory){
product_category=newCategory;
}
void setPrice(int newPrice){
price=newPrice;
}
void setAmount(int newAmount){
amount=newAmount;
}
};
int main(){
Record r1;
r1.setName("beer");
r1.setCategory("alcohol");
r1.setPrice(12);
r1.setAmount(32);
Record r2("carrot", "vegetables", 123, 1932);
std::cout<<r1.getName()<<" "<<r1.getCategory()<<" "<<r1.getPrice()<<" "<<r1.getAmount()<< std::endl;
std::cout<<r2.getName()<<" "<<r2.getCategory()<<" "<<r2.getPrice()<<" "<<r2.getAmount()<< std::endl;
Record r3[2];
std::string a;
float b;
unsigned int c;
for(unsigned int i=0; i<2; ++i){
std::cout<<"input name: ";
std::cin>>a;
r3[i].setName(a);
std::cout<<"input category: ";
std::cin>>a;
r3[i].setCategory(a);
std::cout<<"input price: ";
std::cin>>b;
r3[i].setPrice(b);
std::cout<<"input amount: ";
std::cin>>c;
r3[i].setAmount(c);
}
for(unsigned int i=0; i<2; ++i){
std::cout<<r3[i].getName()<<" "<<r3[i].getCategory()<<" "<<r3[i].getPrice()<<" "<<r3[i].getAmount()<< std::endl;
}
return 0;
}
Error text:
g++ -Wall -c "main.cpp" ( /media/ad/4GB-NTFS/prog/laba2)
main.cpp: In function ‘int main()’:
main.cpp:46:12: error: no matching function for call to ‘Record::Record()’
Record r1;
^
main.cpp:12:1: note: candidate: Record::Record(std::__cxx11::string, std::__cxx11::string, int, int)
Record(std::string newName, std::string newCategory, int newPrice, int newAmount){
^
main.cpp:12:1: note: candidate expects 4 arguments, 0 provided
main.cpp:6:7: note: candidate: Record::Record(const Record&)
class Record{
^
main.cpp:6:7: note: candidate expects 1 argument, 0 provided
main.cpp:54:16: error: no matching function for call to ‘Record::Record()’
Record r3[2];
^
main.cpp:12:1: note: candidate: Record::Record(std::__cxx11::string, std::__cxx11::string, int, int)
Record(std::string newName, std::string newCategory, int newPrice, int newAmount){
^
main.cpp:12:1: note: candidate expects 4 arguments, 0 provided
main.cpp:6:7: note: candidate: Record::Record(const Record&)
class Record{
^
main.cpp:6:7: note: candidate expects 1 argument, 0 provided
Your class doesn't have a default constructor. So when you say:
Record r1;
the compiler doesn't know how to create the r1 object. You either need to provide all the parameters when r is created:
Record r1( "foo", "bar", 1, 2 );
or better completely rethink the design of your program.
You have overriden the constructor of your class, and so there is not one that accepts zero arguments as this requires:
Record r1;
Define a default constructor:
Record() {}
main.cpp:46:12: error: no matching function for call to ‘Record::Record()’
That is, at this point:
Record r1;
You are trying to instantiate the object r1 with a default constructor (Record::Record). Indeed you are not providing any parameter.
Moreover the compiler continues:
note: candidate expects 4 arguments, 0 provided
Following your class interface, the only way to instantiate a Record object is to use the only constructor provided, that is:
Record(std::string, std::string, int, int);
If you want to allow to instantiate an Record object with a default constructor you have to provide it.
C++11 allows you to write:
Record() = default;
In order to define a default constructor.
You have to define a constructor with no parameters.
Record r1 tries to call Record() but it doesn't find it. Just add the extra constructor in your class. It can be empty. This will also solve the same problem with Record r3[2].
P.S. (unrelated to the question, but helpful)
Looking at your code, I suggest you check out member initializer lists for implementing your constructors. Why? See here.

Default constructor missing - but I'm not calling it?

I'm writing a C++ application in which I have a Controller class with two nested structs, defined in my header file as follows:
class Controller {
struct help_message { // controller.hpp, line 19
std::string summary;
std::string details;
help_message(const std::string&, const std::string&);
};
struct player_command {
cmd_t cmd;
help_message help;
// cmd_t is my own typedef, irrelevant for this question
player_command(const cmd_t&, const help_message&);
};
// more members...
};
In my source file, I have this:
Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h) {
cmd = c;
help = h;
};
Controller::help_message::help_message(const std::string& s, const std::string& d) {
summary = s;
details = d;
};
which I thought was fine, but when I compile, this is what I get (controller.cpp line 12 is the first line of the source snippet above):
g++ -g -Wall -std=c++0x -c -o controller.o controller.cpp
controller.cpp: In constructor ‘palla::Controller::player_command::player_command(void (palla::Controller::* const&)(const args_t&), const palla::Controller::help_message&)’:
controller.cpp:12:93: error: no matching function for call to ‘palla::Controller::help_message::help_message()’
controller.cpp:12:93: note: candidates are:
In file included from controller.cpp:7:0:
controller.hpp:22:3: note: palla::Controller::help_message::help_message(const string&, const string&)
controller.hpp:22:3: note: candidate expects 2 arguments, 0 provided
controller.hpp:19:9: note: palla::Controller::help_message::help_message(const palla::Controller::help_message&)
controller.hpp:19:9: note: candidate expects 1 argument, 0 provided
controller.hpp:19:9: note: palla::Controller::help_message::help_message(palla::Controller::help_message&&)
controller.hpp:19:9: note: candidate expects 1 argument, 0 provided
make: *** [controller.o] Error 1
From what I can deduce, the compiler is somewhere trying to call the default constructor of help_message, which doesn't exist. It then tries to match the call up with the constructor I created as well as with the generated copy-constructor and assignment operator, and failing each on the number of arguments.
But what part of my code is calling a default constructor? And how do I fix this error?
The player_command() constructor first default constructs help and then assigns to it:
Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h) {
cmd = c;
help = h;
};
Change that to:
Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h)
: cmd(c),
help(h)
{
};
See Benefits of Initialization lists
The player_command struct contains a help_message (help), and there is no default constructor for help_message. When the player_command constructor is called, by default the help member variable will be default constructed. You are immediately assigning help to the given parameter but this will be after it is default constructed. Instead change the constructor to be something like:
Controller::player_command::player_command(const Controller::cmd_t& c, const help_message& h) : cmd(c), help(h)
{}
This will invoke the copy constructor for both cmd and help member variables instead of doing default construction and then assignment.
You are not using the syntax which avoids the copy constructor. The argument is passed by reference (no copy constructor) but it is indeed copied when assigned to the ivar.
Class::Class(const Variable &var) {
this->var = var; // assignment here, this invokes copy contructor!
}
You should use the following syntax:
Class::Class(const Variable &var) : var(var) { }