I realize the error is coming from using vectors in a custom class, but I have been struggling how to fix them. How do I call vector methods when its part of the class object?
These are the errors I am getting:
Word.cpp: In member function ‘void Word::addPosition(int)’:
Word.cpp:20: error: request for member ‘push_back’ in ‘((Word*)this)->Word::positions’, which is of non-class type ‘std::vector<int, std::allocator<int> >*’
Word.cpp: In member function ‘int Word::getPosition(int)’:
Word.cpp:26: error: request for member ‘size’ in ‘((Word*)this)->Word::positions’, which is of non-class type ‘std::vector<int, std::allocator<int> >*’
Word.cpp:27: error: request for member ‘size’ in ‘((Word*)this)->Word::positions’, which is of non-class type ‘std::vector<int, std::allocator<int> >*’
Word.cpp:29: error: cannot convert ‘std::vector<int, std::allocator<int> >’ to ‘int’ in return
Header
#pragma once
#include <string>
#include <vector>
class Word {
public:
Word();
~Word();
void setWord(std::string);
void addPosition(int);
std::string getWord();
int getPosition(int);
private:
std::string word;
std::vector<int> *positions;
};
Implementation
#include "Word.h"
#include <string>
#include <vector>
Word::Word() {
this->word = "";
this->positions = new std::vector<int>(5);
}
void Word::setWord(std::string s) {
this->word = s;
}
void Word::addPosition(int i) {
this->positions.push_back(i);
}
std::string Word::getWord() {
return this->word;
}
int Word::getPosition(int i) {
if (i < this->positions.size() && i > 0) {
for (int j = 0; j < this->positions.size(); i++) {
if (i == j) {
return positions[j];
}
}
}
return -1;
}
edit: Is this a better way to set up the class? header:
#pragma once
#include <string>
#include <vector>
class Word {
public:
Word();
~Word();
void setWord(std::string);
void addPosition(int);
std::string getWord();
int getPosition(int);
private:
std::string word;
std::vector<int> positions;
};
implementation:
Word::Word(){
word = "";
}
void Word::setWord(std::string s){
this -> word = s;
}
void Word::addPosition(int i){
this -> positions.push_back(i);
}
std::string Word::getWord(){
return this -> word;
}
int Word::getPosition(int i){
if (i < this -> positions.size() && i > 0) {
for (int j = 0; j<this -> positions.size(); i++) {
if (i == j) {
return (this->positions)[j];
}
}
}
return -1;
}
but now I am getting this error:
Undefined symbols for architecture x86_64:
"_main", referenced from:
start in crt1.10.6.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
In addition to @Chris answer, the de facto problem here is that you are using a pointer to a vector instead of a vector directly.
There is no reason to allocate dynamically a vector, because it internally uses dynamic memory to store its elements. The advantage of vector is that it manages its own memory, and that memory its released at the end of its scope: Thats RAII.
Personally I recommend the Going Native 2013 Stroupstrup talk "The Essence of C++". He provides pretty examples and explanations about data management in C++: Data vs Handlers of data.
In Java we differentiate two kinds of data: Basic types (Ints, chars, booleans, etc), and objects (Instances of classes).
Java manages its memory through a Garbage Collector: The Java runtime (The JVM) allocates the memory used by objects on the heap, and what provides you is a pointer to that allocated object. So in Java your variables are really pointers allocated on the stack pointing to the heap memory where the object is allocated (This is directly related with the usual problems which noobs have with Java pass by value). This allows Java to share ownership of object instances easily: It only tracks (via reference counting) how many variables refers to an specific object.
Occasionally the garbage collector look at the program heap and releases the memory used by objects which reference count have dropped to zero (That is, objects which you are not using yet). So, as you can see, The GC provides a non-deterministic way to release/manage the memory.
C++ memory management is dessigned to work in a deterministic way. All variables are declared in a specific scope, which determines its lifetime When the scope of a variable ends, the lifetime of that variable ends, and in the case of objects, its destructor its called to execute the apropiated releasing operations.
Thats known as Resource Acquisition Is Initialization, or RAII.
RAII means that objects manage resources (Memory, file handles, network ports, etc), and the adquisition, use, and release of that resource is directly linked to the lifetime of the object which manages the resource. This provides a deterministic and leak-free system to manage resources: Note that "resources" don't refers to memory only, which is the only resource which a Garbage Collector manages. RAII is, in the 99% of the cases, much more powerfull and secure than a garbage collector.
std::vector
is the tipical example of a class that manages a resource (A dynamically allocated resizable array in its case) through RAII.
As you can see, I havent talk about pointers at all: Pointers have to be used to share ownership of an object, or to allocate a dynamic chunk (Array) of memory. But note that the first case could be (And must be) achieved through smart pointers, and the second through RAII-based containers such as std::vector
.
The problem with your use of a pointer to dynamically-allocate a std::vector
are:
std::vector
manages internally a dynamic array where it allocates the elements, so std::vector
size (That is, what vector fits in the stack) its only the size of the pointer pointing to the array, and two counters (Integers). Don't worry about the size of vector in the stack (Due to possible stackoverflows): The array is allocated on the heap.
Using a pointer to allocate dynamically a vector breaks RAII, because the lifetime of the vector instance is not linked to any scope, its lifetime must be determined by you, when you decide to deallocate (delete
) the vector. Of course manual dynamic memory management its error prone.
Again, I recommend you to view Stroupstrup's talk: He explains this much better than me :)
positions
is a pointer. You need to dereference it in order to get to the base vector:
this->positions->size();
In general, the error you're getting is caused by failing to dereference (because T*
is not a class type; it's a pointer, and pointers are a primitive type).
positions
is a pointer, so you need to use indirection:
this->positions->push_back(i);
Don't use pointers in this situation. You're better off using a stack-allocated vector and initializing it through the constructor:
class Word
{
...
private:
std::string word;
std::vector<int> positions;
};
Word::Word()
: word(""), positions(5) { }
void Word::addPosition(int i)
{
this->positions.push_back(i);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With