I already have a constructor in my .h and .cpp file which takes some arguments but I also need a default argument which I'm not sure how to make because the way I tried it compiles but I get errors when I run my testfile.
This is my .h file
public:
Class();
Class(const std::string &, const int)
void getInfo();
std::string listItem();
private:
std::string name;
int quantity;
This is my .cpp file
Class::Class()
: name(0), quantity(0)
{
Class::Class(const string &nam, const int quant)
: name(nam),quantity(quant)
{
}
void Class::getInfo()
{
cout << "Enter Name: ";
cin >> name
cout << "Enter quantity: ";
cin >> quantity;
}
string Class::listItem()
{
ostringstream outputString;
outputString << getName() << getQuantity();
return outputString.str();
}
And this is the part of my test causing trouble:
const int shortList = 2;
array<Class*, shortList> newList;
for (int i=0; i< 2; i++){
Class *p = new Class();
p->getInfo();
newList[i] = p;
}
cout << "newList contains: " << endl;
for (Class* p : newList)
cout << p->listItem() << endl;
I get : terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Is it a constructor issue or is it some syntax error?
The problem is in the default constructor's initialiser list:
name(0)
This attempts to initialise the string using the constructor taking a C-style string pointer, char const*, with a null pointer value. You then get a runtime error since you're not allowed to pass a null pointer to that constructor.
To initialise the string to be empty, either specify default initialisation (or, pedantically, value-initialisation, which amounts to the same thing for this type)
name()
or leave it out of the initialiser list.
Assuming there are no intentional typos in the above code, there are semi-colons missing in very key locations, as well as curly brace use looking incorrect and missing declarations in the header.
The new lines and/or characters are noted with a comment starting with // added ...
Starting with the header file:
class Class // added
{ // added
public:
Class();
Class(const std::string &, const int); // added semi-colon
void getInfo();
std::string listItem();
private:
std::string name;
int quantity;
}; // added closing curly brace and semi-colon
The .cpp source file:
Class::Class()
: name(""), quantity(0) // modified name initial value to the empty string
{
} // added curly brace
Class::Class(const string &nam, const int quant)
: name(nam),quantity(quant)
{
}
void Class::getInfo()
{
cout << "Enter Name: ";
cin >> name; // added semi-colon
cout << "Enter quantity: ";
cin >> quantity;
}
string Class::listItem()
{
ostringstream outputString;
outputString << getName() << getQuantity();
return outputString.str();
}
Later on the code that is causing fits is:
const int shortList = 2;
array<Class*, shortList> newList;
for (int i=0; i< shortList; i++){ // changed bounds check for i to the const int shortList
Class *p = new Class();
p->getInfo();
newList[i] = p;
}
cout << "newList contains: " << endl;
//
// changed to declare auto instead.
// As a pointer declaration, there is a chance the Class copy constructor is being called
// inside the loop body prior to the dereference. It should not be, but...
// In my opinion, it is much more likely that setting the name to a zero initial value
// in the Class() constructor is the real problem cause as Mike says above.
//
for (auto p : newList)
cout << p->listItem() << endl;
Related
Hi I am unable to use a vector in the constructor. I'm trying to parse a vector that contains [x,y] coordinates into the object.
The errors I've gotten are runtime error and bad alloc.
Is there something I'm missing?
Do I have to use dynamic memory allocation?
ShapeTwoD(Parent Class of Child Class Square):
class ShapeTwoD {
protected:
string name;
bool containsWarpSpace;
vector<string> vect;
private:
public:
ShapeTwoD() {}
ShapeTwoD(string name, bool containsWarpSpace, vector<string> vect) {
this->vect = vect;
this->name = name;
this->containsWarpSpace = containsWarpSpace;
}
Class Square that is a child of ShapeTwoD:
class Square : public ShapeTwoD {
public:
Square() : ShapeTwoD(name, containsWarpSpace, vect) {
this->vect = vect;
this->name = name;
this->containsWarpSpace = containsWarpSpace;
}
~Square() {}
};
Main Function:
vector<string> temp;
string merge;
for (int i = 0; i < 4; i++) {
cout << "Please enter x-ordinate of pt " << i + 1 << " :";
cin >> x;
cout << "Please enter y-ordinate of pt " << i + 1 << " :";
cin >> y;
merge = x + ", " + y;
temp.push_back(merge);
}
Square obj;
obj.setName(shape);
obj.setCoord(temp);
if (specialtype == "ws") {
obj.setContainsWarpSpace(true);
}
else if (specialtype == "ns") {
obj.setContainsWarpSpace(false);
}
myvector.push_back(obj);
temp.clear();
cout << "\nRecords successfully stored. Going back to main menu ...\n"
<< endl;
}
In your Square constructor, you are not passing any arguments:
Square() : ShapeTwoD(name,containsWarpSpace,vect){
^^^^^^^^^^^^^^^^^^^^^^^^^^^
That means that the name, containsWarpSpace and vect refer to the parent class fields, which haven't been initialized yet (because that's the job of the ShapeTwoD constructor). So you are taking uninitialized variables and passing them into the constructor to initialize those same variables. More explicitly what you are doing is
Square():ShapeTwoD(this->ShapeTwoD::name,
this->ShapeTwoD::containsWarpSpace, this->ShapeTwoD::vect){
You should either pass them in:
Square(string name, bool containsWarpSpace, vector<string> vect)
:ShapeTwoD(name,containsWarpSpace,vect) {
or pass a sensible default:
Square() : ShapeTwoD("", false, {}) {
The problem is:
merge = x + ", " + y;
The ", " is a const char[3] (a null terminated character array). As an array, it decays to a pointer (const char *), which is offset by x+y as a result of summation with int. The resultant pointer refers to an unknown memory location. Next null byte is not guaranteed to reside in accessible address range; even if such byte is in an accessible address, the output would not be meaningful; because you are triggering UB.
You can fix it like this:
merge = std::to_string(x) + ", " + std::to_string(y);
Regards,
FM.
Parsing a file and need to add students to a struct vector using an array for student names specific to that course line.
In my course.h file:
struct Course {
std::string name;
int enrollment;
int maxEnrollment;
std::string* students; ///< array of student names
Course(std::string courseName, int maxEnrollmentPermitted);
bool enroll(std::string studentName);
void print(std::ostream& output);
};
In my course.cpp file:
bool Course::enroll(std::string studentName) {
this->students = new std::string[studentName];
if (this->enrollment < this->maxEnrollment) {
this->enrollment++;
return true;
}
else {
return false;
In my source file:
void processEnrollmentRequests(istream& enrollmentRequestsFile, vector<Course>& courses) {
// Read the requests, one at a time, serving each one
string courseName;
enrollmentRequestsFile >> courseName;
while (enrollmentRequestsFile) {
enrollmentRequestsFile >> ws;
string studentName;
getline(enrollmentRequestsFile, studentName);
int pos = search(courses, courseName);
if (pos >= 0) {
// Found a matching course
bool enrolled = courses[pos].enroll(studentName);
if (enrolled) {
cout << studentName << " has enrolled in " << courseName << endl;
}
else {
// course is full
cout << studentName << " cannot enroll in " << courseName << endl;
}
}
else {
// course does not exist
cout << studentName << " cannot enroll in " << courseName << endl;
}
enrollmentRequestsFile >> courseName;
}
}
}
}
I cant seem to add the gathered studentName to the array using this->students = new std::string[studentName]. Getting an error that says must have integral or enumeration type.
new SomeThing[size] is used to declare array. It makes no sense to use a string as the size.
Assuming the size of students is limited to maxEnrollment, you can use this:
if (this->enrollment < this->maxEnrollment) {
this->students[this->enrollment++] = studentName;
return true;
}
else {
return false;
For the sake of completeness, the allocation of students is not the only problem. Given that the code you posted also uses std::vector<Course>, and Course does not follow the rule of 3, using it in a std::vector is highly likely to cause memory corruption, leaks, etc.
Given that you state that students must remain a pointer, the complete fix is to write Course in this manner:
#include <string>
#include <algorithm>
struct Course {
std::string name;
int enrollment;
int maxEnrollment;
std::string* students; ///< array of student names
Course(std::string courseName, int maxEnrollmentPermitted);
bool enroll(std::string studentName);
void print(std::ostream& output);
Course(const Course& rhs);
Course& operator =(const Course& rhs);
~Course();
};
Course::Course(const Course& rhs) : name(rhs.name),
enrollment(rhs.enrollment),
maxEnrollment(rhs.maxEnrollment),
students(new std::string[rhs.maxEnrollment])
{
for (int i = 0; i < maxEnrollment; ++i)
students[i] = rhs.students[i];
}
Course& Course::operator= (const Course& rhs)
{
Course temp(rhs);
std::swap(temp.students, students);
std::swap(temp.maxEnrollment, maxEnrollment);
std::swap(temp.enrollment, enrollment);
std::swap(temp.name, name);
return *this;
}
Course::~Course() { delete [] students; }
Course::Course(std::string courseName, int maxEnrollmentPermitted) :
name(courseName),
enrollment(0),
maxEnrollment(maxEnrollmentPermitted),
students(new std::string[maxEnrollmentPermitted])
{}
Why all of this code? Well, in the code you posted in your question, you are using a std::vector<Course>. The Course class as written could not be safely used in a vector, due to Course having incorrect copy semantics. Thus your error you're getting may have a lot to do with code you stated wasn't yours (the vector<Course>).
The adjustments to Course above now makes Course safe to be used in a vector since the copy semantics (copy constructor, assignment operator, and destructor) have now been implemented to handle the dynamically allocated students member.
Note that absolutely none of this code would be necessary if students were simply a std::vector<std::string> instead of std::string *.
For more reading:
What is the rule of 3?
What is the copy / swap idiom?
I am writing a program where I need to use copy constructor. Since I am novice in using copy constructor I do not know whether my declaration and using of copy constructor is valid or not?
Also here I am facing problem with the display function, the error is ::
error: prototype for 'int Student::display_student()' does not match any in class 'Student'. What is this error?
#include <string>
#include <iostream>
using namespace std;
class Student
{
private:
int rollno;
string name;
public:
Student();
Student(int x, string str);
Student(Student &s);
void display_student();
};
Student::Student()
{
rollno = 0 ;
name = "" ;
}
Student::Student(int x, string str)
{
rollno=x ;
name=str ;
}
Student::Student(Student &s)
{
rollno = s.rollno ;
name = s.name;
}
Student::display_student()
{
cout << "Student Name ::" << name << endl << "Student Roll No. ::" << rollno << endl;
}
int main()
{
Student A;
Student B(09,"Jhonny");
Student C(B);
A.display_student();
B.display_student();
C.display_student();
return 0;
}
You didn't specify the return value in the definition of Student::display_student(). Try:
void Student::display_student()
{
cout << "Student Name ::" << name << endl << "Student Roll No. ::" << rollno << endl;
}
Compiler assumes int Student::display_student() by default. The class declaration contains the prototype for void display_student() but you provided only the definition for function int display_student().
Copy constructor signature uses generally const reference. In your case, you may use the default implementation:
Student(const Student&) = default;
You may also add copy assignment:
Student& operator=(const Student&) = default;
Here's my code. When compiling all the files I get this error, I am not sure what I am doing wrong. Please advise.
Molecule.cpp:7:34: error: return type specification for constructor invalid
//Sunny Pathak
//Molecule.cpp
#include <iostream>
#include "Molecule.h"
using namespace std;
inline void Molecule::Molecule(){
int count;
count = 0;
}//end function
bool Molecule::read(){
cout << "Enter structure: %c\n" << structure << endl;
cout << "Enter full name: %c\n" << name << endl;
cout << "Enter weight : %f\n" << weight << endl;
}//end function
void Molecule::display() const{
cout << structure << ' ' << name << ' ' << weight << ' ' << endl;
}//end function
A constructor has no return type:
class Molecule
{
public:
Molecule(); // constructor. No return type.
bool read();
void display() const;
};
Molecule::Molecule(){
int count;
count = 0;
}//end constructor
Also note that count is local to the body of the constructor, and you are not using it for anything.
You're writing a constructor with a return type. Constructors have no return type. Just change your constructor definition into:
/* void */ Molecule::Molecule()
// ^^^^ Remove this
{
int count;
count = 0;
}
Constructor can not have return type.
update:
inline void Molecule::Molecule(){
^^^
int count;
count = 0;
}//end function
to:
Molecule::Molecule(){
int count;
count = 0;
}//end function
This same error message can occur when :
Class is defined in H file but is missing semicolon
Your CPP file includes the H file, and also begins with the definition for the class constructor.
The compiler will then see your class definition as the return type for the constructor method, and throw this error. If that's the case, then the fix is to add the semicolon.
Note : this is not the case in the OP's example, but the error reported (and hence title of this question post) would be the same.
noob here. Having a doubt while doing an exercise from a book.
The doubt is the following: Why if I use a const std::string * as an argument to a method, the compiler sends me the following error: no matching function for call to 'BankAccount::define(const char [11], const char [11], int)' in the client?
If I swap the prototype and definition of the method to accept as an argument a const std::string & (like I did in the constructor) it's no problem for the compiler.
Client:
// usebacnt.cpp --
#include "BankAccount.h"
#include <iostream>
int main()
{
BankAccount john;
BankAccount mary("Mary Wilkinson", "5000000000"); // balance set to 0 because of default argument
john.display();
mary.display();
john.define("John Smith", "4000000000", 26); // error line
mary.deposit(1000.50);
john.withdraw(25);
john.display();
mary.display();
std::cin.get();
return 0;
}
Class declaration:
// BankAccount.h -- Header file for project Exercise 10.1
#ifndef BANKACCOUNT_H_
#define BANKACCOUNT_H_
#include <string>
class BankAccount
{
private:
std::string fullName;
std::string accountNumber;
double balance;
public:
BankAccount(); // default constructor
BankAccount(const std::string &fN, const std::string &aN, double b = 0.0); // constructor with a default argument
void display() const;
void deposit(double amount);
void withdraw(double amount);
void define(const std::string *pfN, const std::string *paN, double b);
};
#endif
Class implementation:
// methods.cpp -- Compile alongside usebacnt.cpp
#include "BankAccount.h"
#include <iostream>
void BankAccount::display() const
{
using std::cout;
using std::ios_base;
ios_base::fmtflags orig = cout.setf(ios_base::fixed, ios_base::floatfield); // formatting output and saving original
cout.precision(2);
cout << "Full Name: " << fullName << '\n';
cout << "Account Number: " << accountNumber << '\n';
cout << "Balance: " << balance << "\n\n";
cout.setf(orig);
}
void BankAccount::deposit(double amount)
{
if (amount < 0)
{
std::cout << "You can't deposit a negative number! Amount set to zero.";
amount = 0;
}
balance += amount;
}
void BankAccount::withdraw(double amount)
{
if (amount < 0)
{
std::cout << "You can't withdraw a negative number! Amount set to zero.";
amount = 0;
}
if (balance < amount)
{
std::cout << "You can't withdraw more money than you have. Amount set to zero.";
amount = 0;
}
balance -= amount;
}
void BankAccount::define(const std::string *pfN, const std::string *paN, double b)
{
fullName = *fN;
accountNumber = *aN;
balance = b;
}
// constructors
BankAccount::BankAccount() // default constructor
{
fullName = "empty";
accountNumber = "empty";
balance = 0.0;
}
BankAccount::BankAccount(const std::string &fN, const std::string &aN, double b) // constructor with default argument
{
fullName = fN;
accountNumber = aN;
balance = b;
}
Shouldn't the compiler interpret the literal as a string object (like it does with the reference)? So if I say it's a pointer it should pass the address of the string (its first element).
Any help?
Shouldn't the compiler interpret the literal as a string object (like it does with the reference)?
No. Pointers are not references; smack anyone who tells you that they are.
It all comes down to this: std::string is not a string literal. Therefore, when you pass a string literal to a function that takes a std::string, a temporary std::string that holds the contents of the literal must be created. This is done with the conversion constructor of std::string.
A const& is allowed to be initialized from a temporary, which allows conversion constructors to work their magic. A const* must be a pointer, and you're not supposed to get pointers to temporaries. Therefore, const* cannot be magically filled in by a temporary created from a conversion constructor.
You should use a const std::string & instead of a pointer. Or a std::string value if you have C++11 move constructors available.