I have 2 classes:
class CCandidate {
public:
float score;
BitSet documents;
std::vector<std::vector<int> > phrases;
int cardinality;
/** For merging. */
CCandidate()
: score(0.0), documents(1), phrases(1), cardinality(0) {}
/** */
CCandidate(
std::vector<int>& phraseIndices, BitSet& documents,
int cardinality, float score) {
this->phrases.reserve(1);
this->phrases.push_back(phraseIndices);
this->documents = documents;
this->score = score;
this->cardinality = cardinality;
}
};
class PCandidate {
public:
CCandidate * topics;
float coverage;
bool selected;
bool mostGeneral;
bool mostSpecific;
PCandidate(CCandidate * c, float coverage)
: topics(c), coverage(coverage),
selected(true), mostGeneral(true), mostSpecific(true) {}
};
In another class where these classes are used I have something like this:
// ...
std::vector<std::shared_ptr<PCandidate> > phrases(mergeList.size());
for (size_t i = 0; i < mergeList.size(); i++) {
CCandidate * cc = baseTopics.at(mergeList.get(i));
std::wcout << cc->toString() << std::endl;
float coverage = cc->cardinality / result->cardinality;
std::wcout << "coverage=" << coverage << std::endl;
phrases.push_back(std::make_shared<PCandidate>(PCandidate(cc, coverage)));
std::for_each(phrases.begin(), phrases.end(),
[&](const std::shared_ptr<PCandidate>& pc) {
std::wcout << pc->toString() << " "; }); // error
}
}
anotherMethod(phrases);
// ...
Everything is fine with the CCandidate cc (for now in this verson it is a raw pointer), I can print its contents (method toString() not copied in here) and all is fine. Then I construct the PCandidate Object with the make_shared, push it into the phrases vector and when try to access that `phrases' vector to show me the contents of Pcandidate, the topics cluster I get an segmentation fault.
I could not do something like
std::wcout << ptr->topics->phrases.size() << std::endl
where ptr is a pointer to PCandidate. topics is a pointer to CCandidate containing the phrases vector.
It will give me
==10013== Invalid read of size 8
to see the size of the phrases vector in CCandidate.
I'm a little lost as I do not now where to track down the problem, sitting at this since yesterday. It might be a bloody beginners mistake. Is the lack of missing copy constructors / assignment operators? If yes how should they look like? For example copy the entire phrases vector, like a deep copy? I thought the default copy/assignment should be OK so far.
Would be great if somebody can show me the error or how to fix this! Thanks in advance for your time!
You're populating your phrases vector initially with mergeList.size() NULL shared-pointers, then pushing the real ones in after those.
std::vector<std::shared_ptr<PCandidate> > phrases(mergeList.size());
So the first mergeList.size() pointers in your vector are NULL. Lose the initial sizing.
std::vector<std::shared_ptr<PCandidate> > phrases;
If you want to reserve capacity, you can, but ultimately the shared pointers are still going to have to go through their reference counting algorithm either way. I'd skip it and just do the above.
Related
I had this question on a test about a month ago and I still can't seem to understand it completely and quite frankly it's driving me crazy. I will include the question at the bottom. But, it's asking to create a single parameter constructor that creates a new "Vector" (the name of the class) which is the sum of two others. The vector class I made has a function set/get x and set/get y. My hang up is I can't seem to figure out how to make a function that adds the two x's and y's together from vector and vector1 to create a new Vector...call it vector2. I'll include everything I got so far. Thanks to anyone willing to make it through the wall of text as confusing as it must be haha.
Write a class Vertor with the following properties and place the class in a separate header file :
Add member function with a single parameter of another vector and returns a new vector that is the sum of the two (to add vectors you sum the components, for example, Cx = Ax + Bx and Cy = Ay + By).
Write a program that includes the Vector header file, constructs two different vectors and demonstrates the magnitude, angle, and add functions.
Data Members
vector
x component
y component
Member Functions
Set and Get functions for all data members
Magnitude member function
Angle member function (angle = inverse tangent(y / x))
ps I hope I am not doing anything wrong by uploading this and asking I have waited this entire time because I didn't want to break some sort of rule in the community....that I am honestly desperate to become a part of. I've dreamed of doing this my whole life and finally....ahh i digress sorry thanks guys
Oh...my code
#include "Vertor.h"
#include <iostream>
int main()
{
// creates a vector class
Vector vector;
vector.setXcom(4); // sets X
vector.setYcom(12); // sets Y
Vector vector1; // Creates another vector
vector1.setXcom(3);
vector1.setYcom(52);
Vector vector2; // constructs another vector that returns the sum of two other vectors
cout << vector.getXcom() << endl;
cout << vector.getYcom() << endl;
cout << vector.getMag() << endl;
cout << vector.getAng() << endl;
cout << vector1.getXcom() << endl;
cout << vector1.getYcom() << endl;
cout << vector1.getMag() << endl;
cout << vector1.getAng() << endl;
}
#include<iostream>
using namespace std;
// initalize variables
double xcomponent, ycomponent;
double ans, anns, annns;
class Vector // creates Vector class
{
public:
void setXcom(double x) // setX function
{
xcomponent = x;
}
void setYcom(double y) // setY function
{
ycomponent = y;
}
double getXcom() // getX function
{
return xcomponent;
}
double getYcom() // getY function
{
return ycomponent;
}
double getMag() // get magnitude function
{
double ans = sqrt((xcomponent * xcomponent) + (ycomponent * ycomponent));
return ans;
}
double getAng() // get angle function
{
double annns = atan(xcomponent / ycomponent);
return annns;
}
// setnewvec function to make a new vector from two others
void setNewVec(int a, int b)
{
xcomponent = a;
ycomponent = b;
}
// NOT SURE
Vector getNewVec(int a, int b)
{
return a + a;
return b + b;
}
};
So you have an absolutely fundamental misunderstanding or gap in your knowledge about how objects work, and this task will be impossible until you sort that out.
To illustrate here's a simpler example written in the style of your code above. I'll follow that with the same example written as it should be. This example is a simple Person class which has an age 'component'.
int age;
class Person
{
public:
void setAge(int a) { age = a; }
int getAge() { return age; }
};
int main()
{
Person fred;
fred.setAge(22);
Person mary;
mary.setAge(33);
cout << "Fred is " << fred.getAge() << " and Mary is " << mary.getAge() << endl;
}
If you run this program the output will be Fred is 33 and Mary is 33. Both the people have the same age even though you set them as different in the program.
The problem is that although this program has two people it only has one age. So it's literally impossible for the two people to have different ages.
Here's the program written correctly. The crucial difference is that the age variable is inside the class. This means that each Person object gets it's own age.
class Person
{
public:
void setAge(int a) { age = a; }
int getAge() { return age; }
private:
int age;
};
int main()
{
Person fred;
fred.setAge(22);
Person mary;
mary.setAge(33);
cout << "Fred is " << fred.getAge() << " and Mary is " << mary.getAge() << endl;
}
Now the output is Fred is 22 and Mary is 33 as it should be.
First thing you need to do, is to move xcomponent and ycomponent to inside the object. Right now they are global variables which means they share values in all objects you create (and outside object too).
I'm gonna assume you've learned about structures before moving to objects. It's pretty hard to understand object without knowing structures first.
Structures and classes are very similar. They both are containers for variables. Classes are a little more advanced version that usually hides the raw data and instead provides member functions (sometimes called methods) that allow to manipulate the data inside in a more convenient way.
Anyway, when you create a new object of a class, you create it with a new copy all member variables (fields) inside. This way, they can have different values for each object.
Your code is pretty easy to fix in that regard. Just move definition of these variables inside your class.
Old code:
double xcomponent, ycomponent;
double ans, anns, annns;
class Vector // creates Vector class
{
public:
//...
};
New code:
class Vector // creates Vector class
{
double xcomponent, ycomponent;
double ans, anns, annns;
public:
//...
};
Now we can work on the return value.
Your return value of getNewVec is all right. You've declared that you want to return an object of type Vector and this is exactly what you want.
However, the function should also take a single vector as an argument. Right now you have tho arguments int a and int b, none of which is a Vector. We need to change that to Vector otherVector to do what your assignment said.
The call of the function looks like this: someVector.getNewVec(someOtherVector).
When it runs, you have two vectors accessible inside of it. The first of them is the one on which the function was called. You have direct access to its fields. The second one is of course the argument otherVector. You can access its fields through its member functions. (Or you can access directly its private fields because you're in a member function of its class.)
Now you need to construct the new vector.
The simplest way is to just create it and assign the values one by one:
Vector getNewVec(Vector otherVector)
{
Vector newVector;
newVector.setXcom(xcomponent + otherVector.getXcom());
newVector.setYcom(ycomponent + otherVector.getYcom());
return newVector;
}
or:
Vector getNewVec(Vector otherVector)
{
Vector newVector;
newVector.setXcom(xcomponent + otherVector.xcomponent);
newVector.setYcom(ycomponent + otherVector.ycomponent);
return newVector;
}
or if you really want:
Vector getNewVec(Vector otherVector)
{
Vector newVector;
newVector.setXcom(this->getXcom() + otherVector.getXcom());
newVector.setYcom(this->getYcom() + otherVector.getYcom());
return newVector;
}
(this is a pointer the object your inside of. You have access to it from each member function.)
I recommend the second option.
Some additional stuff you can read about if your interested...
(I'm not gonna go into any details here.)
Constructors
You can have a special member function that is called when object it's created that is supposed to set initial values to the fields.
It is written similar to a function, except is doesn't have a return value and it's name is always the same as the name of the class.
Vector(int x, int y)
{
xcomponent = x;
ycomponent = y;
}
That allows to create an abject and assign the values in one line so instead of:
Vector newVector;
newVector.setXcom(12);
newVector.setYcom(42);
you can have:
Vector newVector(12, 42);
You can have more than one constructor with different list of arguments.
You can create an operator instead of a normal function. An operator is a function with specific name and arguments that can be called similarly to built-in mathematical operations.
Operator for addition looks like this:
Vector operator+(Vector otherVector)
//the body is the same as getNewVec
You could call it like a normal member function:
someVector.operator+(someOtherVector)
but a better way of writing it is:
someVector + someOtherVector
I've began making a program in linux with c++ and I'm trying to make it work on windows. It compiles fine, but when run I get this error: "1 [main] Trails of Cold Steel Simulator 8748 cygwin_exception::open_stackdumpfile: Dumping stack trace to Trails of Cold Steel Simulator.exe.stackdump". In the stack trace this exception occurs: "Exception: STATUS_ACCESS_VIOLATION". Here's some code;
#include "Tachi.h"
#include "AutumnLeafCutter.h"
#include <iostream>
#include "Weapon.h"
#include "Armour.h"
#include "Shoes.h"
int main() {
int stats[12] = {15,110,10,4,2,1,2,4,4,3,7,1};
Tachi* Tachi1 = new Tachi(stats, "Tachi");
Tachi1->addEquipment(new PracticeSword());
Tachi1->addEquipment(new LeatherJacket());
Tachi1->addEquipment(new WorkBoots());
Tachi1->addMasterQuartz(new Forcelvl1());
std::string input;
std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
while(input != "q") {
std::cout << "Your current stats are:" << std::endl;
std::cout << "\n";
std::cout << "HP EP STR DEF ATS ADF SPD DEX AGL MOV RNG" << std::endl;
for(int i = 0; i < 12; i += 1) {
std::cout << Tachi1->getBaseStats()[i] << " ";
}
std::cout << "\n\n";
std::cout << "Select a Craft by typing its name:" << std::endl;
std::cout << std::endl;
for(int i = 0; i < Tachi1->getCrafts().size(); i++) {
std::cout << Tachi1->getCrafts()[i]->getName() << std::endl;
}
std::cout << std::endl;
getline(std::cin, input);
if(Tachi1->findCraft(input) != NULL) {
Tachi1->useCraft(input);
} else {
std::cout << "You do not have this craft." << std::endl;
}
std::cout << "\n\n\n";
}
}
Im extremely sorry for any formatting, I've never posted here. The error comes from lines 14,15,16 and 18. When I replaced all the "new xxx()" with NULL and comment out the body of the function with them, the program works. It does this for both addEquipment() and addMasterQuartz(). This is the functions;
void Character::addEquipment(Equipment* e) {
equipment.push_back(e);
std::cin.get();
for(int i = 0; i < 12; i++) {
baseStats[i] += equipment[equipment.size()]->getStatsModifier()[i];
}
}
and
void Character::addMasterQuartz(MasterQuartz* mq) {
masterQuartz = mq;
for(int i = 0; i < 12; i++) {
baseStats[i] += masterQuartz->getStatsModifier()[i];
}
}
Im guessing its a problem with the baseStats[i] += xxx stuff as its the only thing that occurs in both, but I have no idea how to fix that. It could also occur when the stuff is made using new xxx().
I can provide whatever else is needed. Thanks!!!!
EDIT:
I kept testing and the problem seems to lie in the creating of the objects. It worked on linux. Here is one of the object codes, they are all similiar and all crash the program;
#include "Armour.h"
Armour::Armour(int* sm, std::string n):Equipment(sm, n) {}
LeatherJacket::LeatherJacket():Armour(stats, armourName) {}
with header file;
#ifndef ARMOUR_H
#define ARMOUR_H
#include "Equipment.h"
class Armour:public Equipment {
public:
Armour(int* sm, std::string n);
};
class LeatherJacket:public Armour {
int stats[12] = {0,0,0,5,0,0,0,0,0,0,0,0};
std::string armourName = "Leather Jacket";
public:
LeatherJacket();
};
#endif
As soon as I remembered I did this I tried compiling (I think) with -std=c++11, it didnt help.
This is your error
baseStats[i] += equipment[equipment.size()]->getStatsModifier()[i];
By definition this is an out of bounds access on your vector, if a vector has a certain size, then the valid indexes are 0 to size - 1, not 0 to size.
It's fairly obvious that you wanted to access the last item in the vector. You can do that like this
baseStats[i] += equipment[equipment.size() - 1]->getStatsModifier()[i];
but even clearer is to use the back method.
baseStats[i] += equipment.back()->getStatsModifier()[i];
Another way would be to use the e variable you've just pushed onto the vector.
baseStats[i] += e->getStatsModifier()[i];
Adding some detail to the problem spotted by Useless, this code is incorrect.
class LeatherJacket : public Armour {
int stats[12] = {0,0,0,5,0,0,0,0,0,0,0,0};
std::string armourName = "Leather Jacket";
public:
LeatherJacket();
};
LeatherJacket::LeatherJacket() : Armour(stats, armourName) {}
The problem is the order in which things happen. First the Armour constructor is called, then the stats and armourName variables are initialised. So the call to the Armour constructor is using uninitiialised variables and will likely crash.
Several solutions possible, the best is probably to use virtual functions.
Making a couple of assumptions about Equipment (which isn't specified the question) it seems you should do something like this.
// header file
class Equipment
{
public:
virtual ~Equipment() {}
virtual std::string getName() const = 0;
virtual const int* getStatsModifier() const = 0;
};
class Armour : public Equipment
{
};
class LeatherJacket : public Armour
{
static const int stats[12];
public:
virtual std::string getName() const { return "Leather Jacket"; }
virtual const int* getStatsModifier() const { return stats; }
};
// source file
const int LeatherJacket::stats[12] = {0,0,0,5,0,0,0,0,0,0,0,0};
This answer adds pure virtual functions to the base class Equipment (which has become an interface), and implements those functions in LeatherJacket. Because the functions are virtual the appropriate function will always be called and there no need to pass the information down to Equipment. Also since it seems to be per-class constant data, stats has been made static const. Until you get to C++17 static const arrays must be defined in a source file, not the header file, as shown above.
Firstly, I'm going to replace the int[12] arrays with a proper type. Partly so the magic number 12 isn't littered all over the code and hard to change later, and partly because it will behave better (ie, not decay to a pointer in some contexts). This needs C++11.
#include <array>
using Stats = std::array<int, 12>;
To me it looks like Armour should have stats and a name, initialized from the arguments passed to its constructor (which you currently ignore).
Like so:
class Armour: public Equipment {
public:
Stats m_stats;
std::string m_name;
Armour(Stats const& s, std::string const &n) : m_stats(s), m_name(n) {}
};
You were already passing those two arguments to the constructor - you just weren't doing anything with them. Now you are.
This means that when we later have leather, scale, chain and plate subclasses, I can have a pointer of type Armour* and not need to worry about which subclass I'm looking at: the stats are available right there in the base class.
I made the members public, which is generally bad style, to save space. It might not matter for your use. I named the members with the m_ prefix so they can't accidentally get confused with similarly-named non-members. It's broadly good style but not essential.
LeatherArmour doesn't need an additional copy per instance, it just needs one of each for the whole class - so they should be const static members.
class LeatherJacket: public Armour {
static const Stats stats {0,0,0,5,0,0,0,0,0,0,0,0};
static const std::string name{"Leather Jacket"};
public:
LeatherJacket() : Armour(stats, name) {}
};
I made the LeatherJacket-specific stat values static const by writing static const in front of them.
The static means that every LeatherJacket has the same base stats, so you don't need a copy per instance, just one copy for the whole class. It's const because the base stats for leather jackets never change over time. You still have the base class member Armour::m_stats which can change as your individual leather jacket gets damaged, repaired, buffed or whatever.
Again, the LeatherJacket constructor was already passing (the equivalent of) these members to the base class constructor, but now they already exist (see the link above about static storage duration). The original instance variables didn't exist when you used them, because the derived (LeatherJacket) object and its data members aren't really constructed until after the base class subobject.
I have a task to create an object Stos which would feature a heap of objects Obiekt, to which I could add things as I please.
In order to make the program better support dynamic arrays I decided to use a Vector.
The whole implementation seems to run perfectly, the returned value is completely off.
Here is an example with code:
class Obiekt {
private:
int id;
public:
Obiekt::Obiekt(int i) {
id = i;
}
void Obiekt::display() {
cout << "This object has id of: " << id << endl;
}
};
class Stos {
private:
vector < Obiekt* > stos;
public:
Stos::Stos(Obiekt n) {
add(n);
}
void Stos::add(Obiekt n) {
stos.push_back(&n);
}
void Stos::display() {
cout << endl << "===HEAP DISPLAY===" << endl;
for (int i = 0; i < stos.size(); i++) {
stos[i]->display();
}
}
};
void Zad1()
{
Obiekt obj1(5);
Obiekt obj2(23);
Stos s1(obj1);
s1.add(obj2);
s1.display();
getchar();
}
And the outcome being:
===HEAP DISPLAY===
This object has id of: -858993460
This object has id of:9805925
I'm not a cpp expert, and believe the issue is related to the stos.push_back(&n) portion, but I can't catch the moment the id gets so distorted.
It's probably a noob question, so sorry for that on start.
Any help would be amazing.
The issue with your code as O'Neil correctly explained is that you're adding the pointer to a copy of the Obiekt object. So basically, you create your object in main, and pass it to the constructor and the .add function in Stos. You then add the pointer to the vector. When the function finishes, the copy that was passed is destroyed and the pointer in your vector is dangling.
There are two ways to fix this:
1 Pass by reference
This is very simple, basically you just add an ampersand to your function parameters. For instance:
void Stos::add(Obiekt &n) {
stos.push_back(&n);
}
This will ensure that the object isn't destroyed at the end of the function
2 Don't use pointers
Another way of getting your problem to work is to avoid using pointers at all. Your vector will actually copy the contents of the Obiekt object into it. For example:
vector < Obiekt > stos; // notice how we define it without the pointer type
...
void Stos::add(Obiekt n) {
stos.push_back(n); // Creates copy which will then contain the correct value
}
The parameters Obiekt n in
Stos::Stos(Obiekt n) {
add(n);
}
void Stos::add(Obiekt n) {
stos.push_back(&n);
}
are temporary copies destroyed immediatly after each call.
You have to use a reference Obiekt & n instead, or better: by pointer Obiekt * n.
I'm reluctant to assert that the objects exist at the time display is called.
Problem(s)
According to GCC's implementation they don't.
They fall out of scope and are immediately destructed. Give "Obiekt" a non-trivial destructor and this behavior becomes obvious:
~Obiekt(){std::cout << "Bye from: " << it << std::endl;}
Secondarily, note that you shouldn't specify the class membership for functions defined within the class itself (no class_name::function_name(parameters), just function_name(parameters) )
Possible Fix
You (might) want to changing "Stos" such that:
Stos(Obiekt &n) {add(n);}
void add(Obiekt &n) {stos.push_back(&n);}
I'm confused on how to put numerous objects into a class.
So we are required to read in a file that contains a timestamp, employee ID, location number, event code. An example of the input is:
10039865 WHITE99 1 OP
10039876 WHITE99 1 EN
10047500 PINK01 1 EN
10047624 SMITH01 3 EX
10047701 TAN07 2 EN
10048567 DIITZ01 2 OP
10048577 DIITZ01 2 OP
10048587 DIITZ01 2 OP
how do I set those information into objects in a class?
here is what I got so far, and stuck from here. We are required to write a program using an array of pointers to objects.
class Employee {
long timestamp;
string staffID;
int locNum;
string eventCode;
public:
void setValues (long, string, int, string);
};
void Employee::setValues(long timestamp, string staffID, int locNum, string eventCode) {
this->timestamp = timestamp;
this->staffID = staffID;
this->locNum = locNum;
this->eventCode = eventCode;
}
I'm going to leave out a few things, since this looks like homework, but this will get you far.
A couple of things to watch out for:
You aren't using a constructor. Sure a default constructor is nice, but it can help to make your own, especially when starting out.
You should probably use vector instead of an array.
For example:
// Note that I'm making the members public - this is only for demonstration so I don't have to write getters and setters.
class Employee {
public:
Employee(long, std::string, int, std::string);
long timestamp;
std::string staffID;
int locNum;
std::string eventCode;
};
// Here is the constructor.
Employee::Employee(long l, std::string s, int n, std::string s2): timestamp(l), staffID(s), locNum(n), eventCode(s2){}
As for an array - it may be wiser to stick to using a vector of Employee pointers. Such as:
typedef Employee * EmployeePointer;
EmployeePointer employeePtr;
std::vector<EmployeePointer> employeeVec;
Then .push_back() new Employees using your fancy new constructor with a pointer.
employeePtr = new Employee(181213, "Bob", 22, "OP");
employeeVec.push_back(employeePtr);
And simply re-use the employeePtr for new employees.
employeePtr = new Employee(666732, "Sue", 21, "MA");
employeeVec.push_back(employeePtr);
And you will see that a vector (which most other languages refer to as an Array anyway) of pointers to employee objects is created:
for(auto it = employeeVec.begin(); it != employeeVec.end(); it++){
std::cout << (*it)->timestamp << " " << (*it)->staffID << " " << (*it)->locNum << " " << (*it)->eventCode << std::endl;
}
Which displays:
181213 Bob 22 OP
666732 Sue 21 MA
If you can't use vector for whatever reason then implementing this with an array isn't that different, except.
EmployeePointer empPtrArr;
// You'll need to know the size of your array of pointers or else dynamically allocate it, which I don't think you want to do.
empPtrArr = * new EmployeePointer[2];
And You'll have to use a basic for-loop, and not that fancy for(auto ... ) one I used.
Final comments:
For every 'new' there is a 'delete', or you'll have a memory leak
There is at least one #include I left out for you to figure out, which shouldn't be difficult to find
So, here's my code:
/****************************************************************
File: Video.h
Description: class declarations
Author: David && Evan
Class: CSCI 120
Date: 2015 May 13
We hereby certify that this program is entirely our own work.
*****************************************************************/
#ifndef VIDEO_H
#define VIDEO_H
#include <iostream>
#include <string>
#include <vector>
#include "Person.h"
#include "Date.h"
using namespace std;
enum kind {MOVIE, TELEVISION, COMPUTER};
// 'MOVIE' = standalone film of any length, whether it's part of a franchise or not
// 'TELEVISION' = episode from mini- or recurring series
// 'COMPUTER' = online or locally hosted files
/* If need be, we can extend this by adding something for analog home movies,
i.e., camcorder tapes or 8mm film. */
namespace Vids
{
class Video{
public:
Video(); // default constructor
Video(string name, string audience, string location, vector<Person> directors,
vector<Person> actors, Date released);
virtual void display() = 0; // displays information for all objects of Video type
virtual void displayAll() = 0; // displays all information for one object
unsigned char getDirectorSize() const { return directorSize; }
unsigned char getActorSize() const { return actorSize; }
string getName() const { return name; }
string getAudience() const { return audience; }
string getLocation() const { return location; }
Date getReleased() const { return released; }
Date getViewed() const { return viewed; }
string Truncate(string str, size_t width) { // shortens output
if (str.length() > width)
return str.substr(0, width) + "...";
return str;
} // truncate
protected:
short runtimeMinutes;
/* Theoretically runtime could be unsigned, but we might eventually
need negatives for special values. I doubt we'll see one needing
more than 32K minutes, so no worry about overflow. */
unsigned char directorSize;
// number of elements in each vector, shouldn't need more than 255
unsigned char actorSize;
string name; // title of movie
string audience; // PG = "Plenty Guns", PG-13 = "13 or more guns"
string location;
/* Location is a catch-all field for: URL, shelf disc is on, format
type, name of person it is loaned to, etc. */
vector<Person> directors(directorSize);
/* David: I considered using other containers, but none of them
offered any obvious benefits over the vector. */
vector<Person> actors(actorSize);
Date released;
Date viewed;
/* 'viewed' can be used to answer the question: "What haven't i
watched lately?" */
}; // end class Video
} // end namespace Vids
#endif
And compiling [with several other files] gives me this:
$ g++ *.cpp -o Project3
In file included from Computer.cpp:12:
In file included from ./Computer.h:15:
./Video.h:68:29: error: unknown type name 'directorSize'
vector<Person> directors(directorSize);
^
./Video.h:71:26: error: unknown type name 'actorSize'
vector<Person> actors(actorSize);
^
directorSize is declared in the same scope as directors, so why is the compiler not recognizing it?
The line
vector<Person> directors(directorSize);
is not the right syntax for declaring a member variable.
Change it to
vector<Person> directors;
Similarly, change
vector<Person> actors(actorSize);
to
vector<Person> actors;
Given that you can get the number of items in a vector by calling the size() member function, you don't need the member variables:
unsigned char directorSize;
unsigned char actorSize;
Remove them.
Well, this comment is puzzling:
/* Theoretically runtime could be unsigned, but we might eventually
need negatives for special values. I doubt we'll see one needing
more than 32K minutes, so no worry about overflow. */
unsigned char directorSize;
unsigned char maxes out at 255 so if you need up to 32K then you will have to use a different type. In fact it would be better to remove this variable entirely, and retrieve the size by doing directors.size() as needed.
It is possible to initialize the vector in the class definition:
vector<Person> directors{directorSize};
However this would cause undefined behaviour if you hadn't initialized directorSize in the constructor initializer list (because you would be using an uninitialized variable directorSize).
It would be much better to change this to:
vector<Person> directors;
and presumably in your constructor initializer list, or constructor body, you will add some items into this vector.
I'll boil your problem down to a trivial case to demonstrate the problem, along with applying the "m_" member variable prefix popular among some engineers for highlighting a variable that is a "member" of something.
#include <vector>
class Class {
protected:
unsigned char m_directorSize;
std::vector<int> m_directors(m_directorSize);
};
int main()
{
Class x;
}
This does not compile http://ideone.com/VJck4Q and by isolating the problem, we learned a lot.
The line of code:
std::vector<int> m_directors(m_directorSize);
Look at the syntax of this
/typename/ /name/ ( /values/ );
The compiler thinks this is a member-function declaration, which is why it is expecting a type:
std::vector<int> something(unsigned char directorSize);
would declare a member-function called "something" that takes a parameter, directorSize, of type unsigned char. Incidentally: unsigned char is almost guaranteed to be an 8-bit value, capable of storing 0 through 255. That's a terrible choice for a size variable. There is a standard type, size_t for storing non-negative sizes and ssize_t for storing signed sizes.
It's unclear why you think you should be passing directorSize to the vector, but you can't declare a member with a function call.
If you want to shape the default behavior of an object at construction time of your class, you need to use a constructor (or use C++11/C++14, but we don't know if you're doing that):
class Foo_Sized {
std::vector<int> m_vec;
public:
Foo() : m_vec(250) // default construct 250 elements
{}
};
If you were using C++11/14:
class Foo_Sized {
std::vector<int> m_vec = std::vector<int>(250);
};
But if you want to affect one member based on the value of another, the only place you can do that is in a member function, so in this case that means the constructor.
If you're going to create a static array like that, you probably want to be using std::array instead of std::vector - the whole point of vector is that it can grow dynamically.
std::array<int, 250> m_arr;
This declares an array of integers which has a capacity of 250 and has a fixed size. It's faster than a vector but it is always 250 large. You would then have to track the "in-use" count of it and other management overhead yourself.
std::vector<int> vec;
std::cout << vec.size() << '\n'; // prints 0
vec.push(10); // add a value of 10 to the vector.
vec.push(20); // vec is now { 10, 20 }
std::cout << vec.size() << '\n'; // prints 2
vec.push(30); // vec is now { 10, 20, 30 }
std::cout << vec.size() << '\n'; // prints 3
std::cout << vec[0] << '\n'; // prints 10
std::cout << vec[3] << '\n'; // undefined behavior, there is no 3rd element
std::array<int, 3> arr;
std::cout << arr.size() << '\n'; // prints 3: fixed size.
arr[0] = 10; // can't push, fixed size.
arr[1] = 20;
std::cout << arr.size() << '\n'; // still 3, always will be.
arr[2] = 30;
std::cout << arr.size() << '\n'; // still 3, always will be.
std::cout << arr[0] << '\n'; // prints 10
std::cout << arr[3] << '\n'; // compile error: outside fixed size
If you were worrying about memory allocation, you could tell the vector to allocate memory upfront like this:
class Foo_Reserved {
std::vector<int> m_vec;
public:
Foo() : m_vec() // default construct empty
{
m_vec.reserve(250); // reserve memory for 250 elements
}
};
There are a host of other issues with your code, but they aren't directly related to your question so I'm not going to address/highlight them.
But in terms of dealing with your directorSize issues, you should consider providing an accessor that queries the vector or expose a const reference to the vector (this somewhat breaks encapsulation tho since it allows external callers to write code based on assumptions about your internal structure).
class Foo {
public:
using vec_t = std::vector<int>;
protected:
vec_t m_vec;
public:
Foo() : m_vec() // default construct empty
{
}
size_t vecSize() const { return m_vec.size(); }
// or, return a look-don't-touch reference to the vector
const vec_t& getVec() const { return m_vec; }
};
Foo f{}; // C++14 initializer
f.vecSize();
f.getVec().size();