Why can't I add an item to my vector? - c++

I have watched all tutorials and my steps are correct but I still can't get vector to work. Below is my main function.
int main(int argc, char* argv[]) {
std::vector list<test>;
list.push_back(new test());
}
I wish to add a custom custom class which is test. Header is below
#ifndef GIVE_ME_BRAIN_TEST_H
#define GIVE_ME_BRAIN_TEST_H
class test {
public:
test();
};
The class definition is below
#include "test.h"
test::test(){}
#endif //GIVE_ME_BRAIN_TEST_H
However, compiler keeps on spitting out this message.
Googling all suggests my code is correct. What am I doing wrong?

First, std::vector list<test> nerds to be declared as std::vector<test> list instead. That's actually why the compiler complains.
Second, std::vector<test> is a vector containing actual test objects. In your case, new test() returns a pointer to a test object. Your vector doesn't accept pointers to test objects.
Try this instead:
std::vector<test> list;
list.push_back(test());
Otherwise it will keep complaining.
Notice that new is not used anymore. As mentioned in the comments, do not forget that in C++ (unlike in Java, for example) every call to new has to be matched by a call to delete in order to avoid memory leaks. There is no automatic garbage collection. If you forget this, the compiler will not complain, but your program will use more and more memory and potentially (eventually) slow down your system and/or crash.

You wrote
std::vector list<test>;
But the correct syntax is
std::vector<test> list;
Also you can't add a pointer to the vector of objects. You need to dereference it:
auto tmp = new test();
list.push_back(*tmp);

First: Please add #include <vector>
Second: The line std::vector list<test>; need to be replaced with std::vector<test> list
Third: list.push_back take reference as parameter not pointer, so changed as follows:
test *tmp = new test();
list.push_back(*tmp);
The final solution is:
#include <iostream>
#include <vector>
using namespace std;
class test {
public:
test() {
}
};
int main(int argc, char* argv[]) {
std::vector<test> list;
test *tmp = new test();
list.push_back(*tmp);
}

Related

Cannot push_back() a struct into an std::vector<std::shared_ptr<theStruct>> theVector

Hopefully my title isn't too confusing. I'm trying to write a sound manager for my game using SFML. I'm trying to replace my new/delete with the "smart pointer" std::shared_ptr. This is what I have so far.
/* SoundManager.h */
#ifndef SOUNDMANAGER_H
#define SOUNDMANAGER_H
#include <SFML/Audio.hpp>
#include <string>
#include <memory>
class SoundManager
{
public:
~SoundManager();
struct jteSound
{
sf::Sound snd;
sf::SoundBuffer sndBuffer;
std::string name;
};
//Load a new sound from path and store it in audio bank bnk.
//Banks are simply std::vectors of type jteSound.
void registerNewSound(std::vector<std::shared_ptr<jteSound>> &bnk, std::string path, std::string sndName);
//Footsteps bank
std::vector<std::shared_ptr<jteSound>> bnkFootsteps;
};
#endif // SOUNDMANAGER_H
/* SoundManager.cpp */
#include "SoundManager.h"
#include <stdlib.h>
SoundManager::~SoundManager()
{
/*
//Cleanup each sound bank that we use.
for (std::vector<jteSound*>::iterator it = bnkFootsteps.begin(); it != bnkFootsteps.end(); ++it) {
delete *it;
}
*/
}
void SoundManager::registerNewSound(std::vector<std::shared_ptr<jteSound>> &bnk, std::string path, std::string sndName)
{
static int counter = 0;
for (int i = counter; counter <i+1; counter++) {
bnk.push_back(jteSound);
bnk[i]->name = sndName;
bnk[i]->sndBuffer.loadFromFile(path);
bnk[i]->snd.setBuffer(bnk[i]->sndBuffer);
}
}
bnk.push_back(jteSound); gives me a compiler error. If I remove the line, the program compiles, but crashes. I have tried things like emplace_back() or jteSound* or new jteSound, but nothing works. I always get a lengthy compiler error or immediate runtime crash. When I use regular pointers and new/delete, see https://bpaste.net/show/fa684f2f2d5e and https://bpaste.net/show/c74ac701ce7a, the code works as expected. Any thoughts appreciated!
The type of the elements inside your std::vector is std::shared_ptr<jteSound> which means that std::vector::push_back will accept only instances of that type.
To make your code work you have two options. The first is using std::make_shared helper function as follows:
bnk.push_back(std::make_shared<jteSound>());
// the equivalent counterpart is:
bnk.push_back(std::shared_ptr<jteSound>(new jteSound));
The second is using std::vector::emplace as follows:
bnk.emplace(bnk.end(), new jteSound);
As the comments below warn, using the second option is risky because it can cause memory leak when the new jteSound succeeds but the std::vector::emplace has to reallocate memory and fails.

passing an array into a class function from another class's constructor

Sorry for the confusing title, basically I have created two classes, one is an object, and the other being a box that contains an array of such objects. so what I want to do is create a function/constructor inside the object class that takes in an array of ints and stores them inside the box. I want to be able to call this function through the box class constructor to initialize these objects. So ive tried something like below but it isnt working at all, since only the first value of the array gets passed through. What am I doing wrong?
#include <iostream>
#include <string>
class object{
string objectName;
int values[];
public:
void createObject(int[]);
}
class Box{
object objects[100];
public:
Box();
}
Box::Box (void){
int array1[2];
int array2[15];
object[1].createObject(array1);
object[2].createObject(array2);
}
Object::Object(int Values[]){
values = Values;
}
You should really use std::vector. The problem with arrays is that they decay to pointers when passed as arguments to functions. As a consequence, If you want to store a private copy of the elements you are forced to use heap-allocated objects and consequently do memory management by hand (with all the pain it causes).
It is much better to rely on data members that permit applying the rule of zero.
Here's a tentative solution:
#include <iostream>
#include <string>
#include <vector>
class object {
public:
object(std::vector<int> const& v, std::string const& object_name): v_(v.begin(), v.end()), object_name_(object_name) {}
private:
std::vector<int> v_;
std::string object_name_;
};
class box {
public:
box(std::vector<object> const& objects): objects_(objects) {};
private:
std::vector<object> objects_;
};
I recommend you instead use a std::vector. Arrays don't really work well being passed to functions. When you define Object::Object(int Values[]) you are simply passing the first element of this array by value. If you were to use vectors, the function would look like this:
Object::Object(std::vector<int> &Values):
values(Values)
{
}
The problem with the code is in your thinking on what the array is. In C++, all an array is, is a memory pointer. The language allows you to pass an index into the array pointer to access whatever chunk of data lives at that index.
Whenever you pass arrays between functions or classes, pass the array name only. It will be interpreted as a pointer, and won't copy any data. When you do this, you must also pass the length of the array.
Granted, most people stick with vector<> because it's easier, takes care of memory leaks (mostly) and is VERY efficient. But I like doing it myself. It's good for you. I would try:
#include <iostream>
#include <string>
class Object
{
string _objectName;
int *_values;
int _myLength;
Object();
~Object();
void createObject(int *pValues, int arrLength);
}
class Box
{
_Object objects[100];
Box();
}
Box::Box(void) {
int array1[2];
int array2[15];
object[1].createObject(array1, 2);
object[2].createObject(array2, 15);
}
Object::Object() {
_values = null_ptr;
_myLength = 0;
}
Object::~Object() {
delete[] _values;
}
void Object::createObject(int *pvalues, int arrLength) {
_myLength = arrLength;
_values = new int[_myLength];
for(int ndx=0; ndx<arrLength; ndx++) {
_values[ndx] = pvalues[ndx];
}
}
-CAUTION-
I just adapted your code you provided, and added some conventions. There are a couple places in the code where I'm not sure what the purpose is, but there you go. This should give you a good head start.

How to store a variable in a header, to use in the main cpp?

I tried asking this question, it was a bit more fuzzy on the details, but now I arrived home and I hope I can explain myself better.
Say, I have a class, in this case, TestClass, I declared its constructor and methods in TestClass.h already. Now, I want to create a new array of these elements, and store them somewhere, to load in to my main.cpp, when I want to.
What I tried doing, is, doing this in a new header, I called Contents Table.h. Here, I tried making an array of these TestClass elements. However, I don't really know, how to go about properly doing this.
Testclass.h
#pragma once
#include <string.h>
#include <iostream>
using namespace std;
class TestClass
{
private:
string name;
string description;
public:
TestClass()
{
name = "";
description = "";
}
TestClass(string name, string description)
{
this->name = name;
this->description = description;
}
~TestClass()
{
}
};
And here is the Contents Table, where I want to store my data, that I manually write in, I had two ideas about doing this, not sure which one is feasible:
First idea:
ContentsTable.h
#include "Testclass.h"
TestClass* buildData(void)
{
TestClass* World = new TestClass[5];
World[0] = TestClass("A", "A");
//Etc, fill the rest up.
return World;
}
And in the main.cpp, I'd call this function, like
#include "Contents Table.h"
//...
TestClass* DataArray = buildData();
Second idea:
ContentsTable.h
#include "Testclass.h"
namespace DataArray2
{
extern TestClass* DataArray2 = new TestClass[5];
DataArray2[0] = TestClass("A", "A");
};
And I'd declare it again in the main.cpp, but the second one things, I'm trying to redeclare the DataArray2, when I try giving one if its elements value. (Again, I'm sure it's my fault with this, sorry, if it seems like a really banal code, I haven't been learning for long.)
Not sure if this meets your requirements, but I'd make buildData look like this (C++11 solution):
#include <vector>
using std::vector;
/*Define TestClass*/
vector<TestClass> buildData() {
vector<TestClass> v;
v.emplace_back("A", "A");
return v;
}

Where to allocate one time use class?

Lets consider the following code:
void main(int argc, char* argv[])
{
Foo foo;
//at this point I don't need foo any more
//a lot of stuff here
}
If I only need foo only for short amount of time,isn't it would be better to allocate it on a heap and delete before executing rest of the code?
No, it's better to write an inner scope.
int main()
{
{
Foo foo;
// use foo
}
// more code
}
But doing this should be a hint that it might be better to put foo in a completely separate function.
There's no reason to use heap allocation here though. That solution would be worse than the problem.

what is a good place to put a const in the following C++ statement

Consider the following class member:
std::vector<sim_mob::Lane *> IncomingLanes_;
the above container shall store the pointer to some if my Lane objects. I don't want the subroutins using this variable as argument, to be able to modify Lane objects.
At the same time, I don't know where to put 'const' keyword that does not stop me from populating the container.
could you please help me with this?
thank you and regards
vahid
Edit:
Based on the answers i got so far(Many Thanks to them all) Suppose this sample:
#include <vector>
#include<iostream>
using namespace std;
class Lane
{
private:
int a;
public:
Lane(int h):a(h){}
void setA(int a_)
{
a=a_;
}
void printLane()
{
std::cout << a << std::endl;
}
};
class B
{
public:
vector< Lane const *> IncomingLanes;
void addLane(Lane *l)
{
IncomingLanes.push_back(l);
}
};
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(&l1);
b.addLane(&l2);
b.IncomingLanes.at(1)->printLane();
b.IncomingLanes.at(1)->setA(12);
return 1;
}
What I meant was:
b.IncomingLanes.at(1)->printLane()
should work on IncomingLanes with no problem AND
b.IncomingLanes.at(1)->setA(12)
should not be allowed.(In th above example none of the two mentioned methods work!)
Beside solving the problem, I am loking for good programming practice also. So if you think there is a solution to the above problem but in a bad way, plase let us all know.
Thaks agian
A detour first: Use a smart pointer such shared_ptr and not raw pointers within your container. This would make your life a lot easy down the line.
Typically, what you are looking for is called design-const i.e. functions which do not modify their arguments. This, you achieve, by passing arguments via const-reference. Also, if it is a member function make the function const (i.e. this becomes const within the scope of this function and thus you cannot use this to write to the members).
Without knowing more about your class it would be difficult to advise you to use a container of const-references to lanes. That would make inserting lane objects difficult -- a one-time affair, possible only via initializer lists in the ctor(s).
A few must reads:
The whole of FAQ 18
Sutter on const-correctness
Edit: code sample:
#include <vector>
#include <iostream>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
#include <vector>
#include <iostream>
#include <memory>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
class Lane
{
private:
int a;
public:
Lane(int h):a(h){}
void setA(int a_) // do you need this?
{
a=a_;
}
void printLane() const // design-const
{
std::cout << a << std::endl;
}
};
class B
{
// be consistent with namespace qualification
std::vector< Lane const * > IncomingLanes; // don't expose impl. details
public:
void addLane(Lane const& l) // who's responsible for freeing `l'?
{
IncomingLanes.push_back(&l); // would change
}
void printLane(size_t index) const
{
#ifdef _DEBUG
IncomingLanes.at( index )->printLane();
#else
IncomingLanes[ index ]->printLane();
#endif
}
};
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(l1);
b.addLane(l2);
//b.IncomingLanes.at(1)->printLane(); // this is bad
//b.IncomingLanes.at(1)->setA(12); // this is bad
b.printLane(1);
return 1;
}
Also, as Matthieu M. suggested:
shared ownership is more complicated because it becomes difficult to
tell who really owns the object and when it will be released (and
that's on top of the performance overhead). So unique_ptr should be
the default choice, and shared_ptr a last resort.
Note that unique_ptrs may require you to move them using std::move. I am updating the example to use pointer to const Lane (a simpler interface to get started with).
You can do it this way:
std::vector<const sim_mob::Lane *> IncomingLanes_;
Or this way:
std::vector<sim_mob::Lane const *> IncomingLanes_;
In C/C++, const typename * and typename const * are identical in meaning.
Updated to address updated question:
If really all you need to do is
b.IncomingLanes.at(1)->printLane()
then you just have to declare printLane like this:
void printLane() const // Tell compiler that printLane doesn't change this
{
std::cout << a << std::endl;
}
I suspect that you want the object to be able to modify the elements (i.e., you don't want the elements to truly be const). Instead, you want nonmember functions to only get read-only access to the std::vector (i.e., you want to prohibit changes from outside the object).
As such, I wouldn't put const anywhere on IncomingLanes_. Instead, I would expose IncomingLanes_ as a pair of std::vector<sim_mob::Lane *>::const_iterators (through methods called something like GetIncomingLanesBegin() and GetIncomingLanesEnd()).
you may declare it like:
std::vector<const sim_mob::Lane *> IncomingLanes_;
you will be able to add, or remove item from array, but you want be able to change item see bellow
IncomingLanes_.push_back(someLine); // Ok
IncomingLanes_[0] = someLine; //error
IncomingLanes_[0]->some_meber = someting; //error
IncomingLanes_.erase(IncomingLanes_.end()); //OK
IncomingLanes_[0]->nonConstMethod(); //error
If you don't want other routines to modify IncomingLanes, but you do want to be able to modify it yourself, just use const in the function declarations that you call.
Or if you don't have control over the functions, when they're external, don't give them access to IncomingLanes directly. Make IncomingLanes private and provide a const getter for it.
I don't think what you want is possible without making the pointers stored in the vector const as well.
const std::vector<sim_mob::Lane*> // means the vector is const, not the pointer within it
std::vector<const sim_mob::Lane*> // means no one can modify the data pointed at.
At best, the second version does what you want but you will have this construct throughout your code where ever you do want to modify the data:
const_cast<sim_mob::Lane*>(theVector[i])->non_const_method();
Have you considered a different class hierarchy where sim_mob::Lane's public interface is const and sim_mob::Really_Lane contains the non-const interfaces. Then users of the vector cannot be sure a "Lane" object is "real" without using dynamic_cast?
Before we get to const goodness, you should first use encapsulation.
Do not expose the vector to the external world, and it will become much easier.
A weak (*) encapsulation here is sufficient:
class B {
public:
std::vector<Lane> const& getIncomingLanes() const { return incomingLanes; }
void addLane(Lane l) { incomlingLanes.push_back(l); }
private:
std::vector<Lane> incomingLanes;
};
The above is simplissime, and yet achieves the goal:
clients of the class cannot modify the vector itself
clients of the class cannot modify the vector content (Lane instances)
and of course, the class can access the vector content fully and modify it at will.
Your new main routine becomes:
int main()
{
Lane l1(1);
Lane l2(2);
B b;
b.addLane(l1);
b.addLane(l2);
b.getIncomingLanes().at(1).printLane();
b.getIncomingLanes().at(1).setA(12); // expected-error\
// { passing ‘const Lane’ as ‘this’ argument of
// ‘void Lane::setA(int)’ discards qualifiers }
return 1;
}
(*) This is weak in the sense that even though the attribute itself is not exposed, because we give a reference to it to the external world in practice clients are not really shielded.