I've got a vector of objects (apples) and I need a pointer to jump through every element, to print "size" value on every object in "apples". I tried vector::iterator, pointing whole vector but I still cannot get correct solution
#include <iostream>
#include <vector>
class Apple{
public:
int size;
Apple(int size): size(size){}
void print(){
std::cout<<size;
}
};
std::vector<Apple*>apples = {new Apple(21), new Apple(37), new Apple(66)};
Apple* ptr = apples[0];
void nextApple(){
ptr++;
ptr->print(); //returns 0
}
int main()
{
nextApple();
return 0;
}
Big thank You for any help!
To iterate through any T[] array using a pointer, you need to use a T* pointer, and you need to point it initially at the address of the 1st element, not the value of the element.
Your vector's element type is T = Apple*, not T = Apple, so you need to use an Apple** pointer rather than an Apple* pointer, eg:
#include <iostream>
#include <vector>
class Apple{
public:
int size;
Apple(int size) : size(size){}
void print(){
std::cout << size << std::endl;
}
};
std::vector<Apple*> apples = {new Apple(21), new Apple(37), new Apple(66)};
Apple** ptr = &apples[0];
void nextApple(){
++ptr;
(*ptr)->print();
}
int main()
{
nextApple();
return 0;
}
Using an iterator instead (or even an index) would have worked just fine, eg:
#include <iostream>
#include <vector>
class Apple{
public:
int size;
Apple(int size): size(size){}
void print(){
std::cout << size << std::endl;
}
};
std::vector<Apple*> apples = {new Apple(21), new Apple(37), new Apple(66)};
std::vector<Apple*>::iterator iter = apples.begin();
// or: size_t index = 0;
void nextApple(){
++iter;
(*iter)->print();
// or:
// ++index;
// apples[index]->print();
}
int main()
{
nextApple();
return 0;
}
That being said, using a vector of raw Apple* pointers is not a good idea. You have to delete the Apple objects when you are done using them. At the very least, you should wrap the pointers in std::unique_ptr to avoid memory leaks, eg:
#include <iostream>
#include <vector>
#include <memory>
class Apple{
public:
int size;
Apple(int size): size(size){}
void print(){
std::cout << size << std::endl;
}
};
std::vector<std::unique_ptr<Apple>> apples = {std::make_unique<Apple>(21), std::make_unique<Apple>(37), std::make_unique<Apple>(66)};
auto *ptr = &apples[0];
// or: auto iter = apples.begin();
// or: size_t index = 0;
void nextApple(){
++ptr;
(*ptr)->print();
// or:
// ++iter;
// (*iter)->print();
// or:
// ++index;
// apples[index]->print();
}
int main()
{
nextApple();
return 0;
}
But really, just get rid of the dynamic allocation altogther, you don't need it in this example:
#include <iostream>
#include <vector>
class Apple{
public:
int size;
Apple(int size): size(size){}
void print(){
std::cout << size << std::endl;
}
};
std::vector<Apple> apples = {21, 37, 66};
Apple* ptr = &apples[0];
// or: auto iter = apples.begin();
// or: size_t index = 0;
void nextApple(){
++ptr;
ptr->print();
// or:
// ++iter;
// iter->print();
// or:
// ++index;
// apples[index].print();
}
int main()
{
nextApple();
return 0;
}
The code in the question is not idiomatic C++; more like a Java design. In C++ iterators just work:
void show_apples() {
std::vector<Apple> apples =
{ Apple(21), Apple(37), Apple(66) };
for (auto iter = apples.begin(); iter != Apples.end(); ++iter)
std::cout << iter->size << ' ';
std::cout << '\n';
}
Related
I need to make an array of string where I can store either 3 or 5 words like {"banana, peach, pear"}, or {"orange", "pear", "silantro", "ginger", "mandarine"}.
I'm confused if I should make an array of string pointer(to dynamically allocate the memory depending on the size of the array-3 or 5), or just have an array of string with the statically allocated memory of 5. And how to initialize it/set it to null/use it in the constructors.
I'm not allowed to use vector.
When I declared an array of size 5, the problem started in the default constructor.
I don't know how to set it to null...
// string multiple_fruits[5]
// multiple_fruits[] = { nullptr, };
So I'm using an array of string pointer here, is there a better way?
What am I doing wrong?? HAAAALP
//.h file
class Fruit {
char* single_fruit;
string* multiple_fruits;
int num_Fruits;
};
//.cpp file
Fruit::Fruit() {
single_fruit = nullptr;
multiple_fruits = nullptr;
num_Fruits = 0;
}
Fruit::Fruit(const char* singlefruit, string* multiplefruits, int numFruits) {
single_fruit = new char[strlen(singlefruit) + 1];
strcpy_s(single_fruit, strlen(singlefruit) + 1, singlefruit);
multiple_fruits = new string[numFruits];
for (int i = 0; i < numFruits; i++) {
multiple_fruits[i] = multiplefruits[i];
}
num_fruits = numFruits;
}
int main() {
Fruit A;
A("apple", {"banana", "peach", "pear"}, 3)
Fruit B;
B("lemon", {"orange", "pear", "silantro", "ginger", "mandarine"}, 5);
return 0;
}
My approach is to use std::string and std::initializer_list for this:
#include <string>
#include <initializer_list>
class Fruit {
public:
Fruit(const std::string &singlefruit, const std::initializer_list<std::string> &multiplefruits) : single_fruit{singlefruit}, multiple_fruits{new std::string[multiplefruits.size()]}, num_Fruits{multiplefruits.size()} {
for (std::size_t i = 0; i < num_Fruits; ++i) {
multiple_fruits[i] = *(multiplefruits.begin() + i);
}
}
~Fruit() {
delete[] multiple_fruits;
}
private:
std::string single_fruit;
std::string *multiple_fruits;
std::size_t num_Fruits;
};
int main() {
Fruit A("apple", {"banana", "peach", "pear"});
Fruit B("lemon", {"orange", "pear", "silantro", "ginger", "mandarine"});
}
I allocated memory for the elements and deleted the memory in the destructor.
You can't declare a variable in one line and call the constructor in the next line.
Here's one way using a proper declaration of the array argument to the constructor.
#include <algorithm> // std::copy
#include <iterator> // std::begin, std::end
#include <string>
#include <iostream>
template<size_t N>
class Fruit {
public:
Fruit();
Fruit(const std::string& singlefruit, const std::string (&multiplefruits)[N]);
size_t size() const;
private:
std::string single_fruit;
std::string multiple_fruits[N];
};
template<size_t N>
Fruit<N>::Fruit() {}
template<size_t N>
Fruit<N>::Fruit(const std::string& singlefruit, const std::string (&multiplefruits)[N])
: // colon indicates the start of the member initializer list
single_fruit(singlefruit)
{
std::copy(std::begin(multiplefruits), std::end(multiplefruits), multiple_fruits);
}
template<size_t N>
size_t Fruit<N>::size() const { return N; }
int main() {
Fruit A("apple", {"banana", "peach", "pear"});
std::cout << A.size() << '\n';
Fruit B("lemon", {"orange", "pear", "silantro", "ginger", "mandarine"});
std::cout << B.size() << '\n';
}
Output:
3
5
This question already has an answer here:
Initializing an std::array of non-default-constructible elements?
(1 answer)
Closed 2 years ago.
I want to initialize a array of 1 million objects on stack, I need to write one million &i in the following code.
Is there any other good way.
#include <iostream>
class A{
public:
A(int* p)
: p_(p){
std::cout << "A" << std::endl;
}
private:
int *p_;
};
int main(){
int i;
A a[3] = {&i, &i, &i};
}
#include <iostream>
#include <type_traits>
class A{
public:
A(int* p)
: p_(p){
std::cout << "A" << std::endl;
}
private:
int *p_;
};
int main(){
using elemType = std::aligned_storage<sizeof(A), alignof(A)>::type;
const size_t count = 1000000;
int i;
elemType a[count];
for(int idx = 0; idx < count: ++idx) {
new (&a[idx]) A(&i);
}
...
for(int idx = 0; idx < count: ++idx) {
reinterpret_cast<A&>(a[idx]).~A();
}
return 0;
}
C++ new operator can be used to call constructor on a preallocated memory:
#include <iostream>
#include <cstddef>
#include <cstdint>
class A{
public:
A(int* p)
: p_(p){
std::cout << "A" << std::endl;
}
private:
int *p_;
};
int main(){
int i;
uint8_t buf[1000000 * sizeof(A)];
A* pa = reinterpret_cast<A*>(buf);
for (size_t n = 0; n < 1000000; n++) {
new (&pa[n]) A(&i);
}
return 0;
}
You could use std::vector and initialize is with a million elements
std::vector<A> a(1000000, &i);
In the class constructor, I am initializing other objects and pushing these objects to my class vector member. From what I understand, the vector create a copy of the object and stores it so that it doesn't go out of scope. However, when verifying the objects in another class function, they are not initialized anymore. Here's a example code to explain the behaviour:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
class Square {
private:
int size_ = 0;
int colour_ = 0;
public:
Square(){
size_ = 0;
colour_ = 0;
}
void init(int size, int colour) {
size_ = size;
colour_ = colour;
}
int get_size() { return size_; }
};
class SetSquares {
private:
std::vector<Square> squares_;
int number_;
public:
SetSquares(): number_(0) {}
void init(int num) {
number_ = num;
squares_.clear();
squares_.resize(num);
for (int i=0; i < num; i++) {
Square square;
square.init(i, i);
squares_.push_back(square);
}
}
void sample(int i) {
if (i >= number_) { return; }
std::cout << "Square size is: " << squares_[i].get_size() << std::endl;
}
};
int main()
{
SetSquares set_of_squares;
set_of_squares.init(7);
set_of_squares.sample(4);
return 0;
}
resize(n) will create n default constructed elements in a vector and push_back will append new elements after those n elements. Use reserve and push_back or resize and index operator as suggested in comment.
I´m quiet new on C++ and currently learning to understand smart pointers.Therefore I`m currently working on a little console-program for inserting,searching and deleting songs ... for learning purposes to get used to the stuff =)
Here is my code:
Song.hpp
#pragma once
#include <vector>
#include <memory>
#include <string>
class Song
{
public:
typedef std::unique_ptr<Song> pSong;
public:
Song();
~Song();
void setTitle(std::string title);
void setArtist(std::string artist);
void checkSong(std::string item, int iterator);
void get();
private:
std::string _title;
std::string _artist;
};
Song.cpp
#include "Song.hpp"
#include <iostream>
Song::Song()
{
}
Song::~Song()
{
}
void Song::setTitle(std::string title)
{
_title = title;
}
void Song::setArtist(std::string artist)
{
_artist = artist;
}
void Song::checkSong(std::string item, int iterator)
{
if (_artist == item || _title == item)
{
std::cout << "Item found on Slot: " << iterator << std::endl;
}
else
{
std::cout << "No item found!" << std::endl;
}
}
void Song::get()
{
std::cout << _artist << " - " << _title << std::endl;
}
Main.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include "Song.hpp"
//prototype
void IntVector();
void SongVector();
Song* setSong(std::string title, std::string artist);
void find(std::string item, std::vector<Song::pSong> v);
std::vector<Song::pSong> SongList;
int main()
{
int k;
SongVector();
std::cin >> k;
return 0;
}
void IntVector()
{
// Create Vector
std::vector<std::unique_ptr<int>> v;
// Create a few unique_ptr<int> instances and fill them with ints
v.push_back(std::unique_ptr<int>(new int(30)));
v.push_back(std::unique_ptr<int>(new int(600)));
v.push_back(std::unique_ptr<int>(new int(200)));
v.push_back(std::unique_ptr<int>(new int(20)));
v.push_back(std::unique_ptr<int>(new int(200)));
v.push_back(std::unique_ptr<int>(new int(160)));
v.push_back(std::unique_ptr<int>(new int(4)));
v.push_back(std::unique_ptr<int>(new int(5)));
v.push_back(std::unique_ptr<int>(new int(315)));
// define vector<int> for storing values of the unique_ptr
std::vector<int> intList;
for (int i = 0; i < v.size(); i++)
{
// get memory-adress of each element
auto result = v[i].get();
// store value of result-pointer in Vector
intList.push_back(*result);
std::cout << *result << std::endl;
}
// Sort int of new Vector
std::sort(intList.begin(), intList.end());
// Loop through intList and cout
for (int i = 0; i < intList.size(); i++)
{
std::cout << intList[i] << std::endl;
}
}
void SongVector()
{
Song* first = setSong("Afroki","Steve Aoki");
Song* secound = setSong("Hype", "Steve Aoki");
Song* third = setSong("Madness", "Steve Aoki");
Song* fourth = setSong("Cake Face", "Steve Aoki");
SongList.push_back(Song::pSong(first));
SongList.push_back(Song::pSong(secound));
SongList.push_back(Song::pSong(third));
SongList.push_back(Song::pSong(fourth));
for (const auto& song : SongList)
{
song->get();
}
find("Madness", SongList);
}
Song* setSong(std::string title, std::string artist)
{
Song* song = nullptr;
song = new Song;
song->setArtist(artist);
song->setTitle(title);
return song;
}
void find(std::string item, std::vector<Song::pSong> v)
{
int i = 0;
for (const auto& song : v)
{
song->checkSong(item,i);
i++;
}
}
I got following error:
std::unique_ptr<Song,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
1> with
1> [
1> _Ty=Song
1> ]
I found out, that this error only occurs, when calling my find(...)-method, so I´m guessing that somewhere in there is my mistake, but I just cant find out, what Ive done wrong. Would appreciate your help.
std::unique_ptr provide unique ownership (hense the name) which means beside other you cannot copy instance of std::unique_ptr - which would mean shared ownership. When you passing std::vector<std::unique_ptr<whatever>> by value you creating a copy of vector instance, which tries to copy each element. So simplest solution would be to pass std::vector instance by const reference (as you do not have intention to modify vector):
void find( const std::string &item, const std::vector<Song::pSong>& v);
beside fixing your problem passing by (const) reference is more efficient for non trivial objects, so you can also use it for std::string
in your intVector() function:
for (int i = 0; i < v.size(); i++)
{
// get memory-adress of each element
auto result = v[i].get();
// store value of result-pointer in Vector
intList.push_back(*result);
std::cout << *result << std::endl;
}
you do not really need to get raw pointer, just use std::unique_ptr itself:
for (int i = 0; i < v.size(); i++)
{
// get smart pointer for each element
const auto &result = v[i];
// store value of result-pointer in Vector
intList.push_back(*result);
std::cout << *result << std::endl;
}
void find(std::string item, std::vector<Song::pSong> v)
You need to pass vectors by reference. Add &.
void find(std::string item, std::vector<Song::pSong>& v)
Don't forget to also change the prototype of the function.
In the following example I remove from list some elements in the range for which the application of pr2 to it return true.
m_list.remove_if(pr2(*tmp_list));
It seems to me it is necessary to delete this objects, which was removed above, becase when I create it I use "new" (new CRectangle()). How I can do this? I don't know which (and how much) elements will be remove after remove_if.
// test_cconnection.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <conio.h>
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
class CDrawObject
{
public:
virtual ~CDrawObject()
{
cout << "Drop CDrawObject: " << id_ << endl;
}
int getId() const
{
return id_;
}
virtual void draw()
{
}
protected:
static int id;
int id_;
};
class CRectangle : public CDrawObject
{
public:
CRectangle()
{
id_ = id++;
}
~CRectangle()
{
cout << "Drop CRectangle: " << id_ << endl;
}
virtual void draw()
{
cout << "CRectangle, id: " << id_ << endl;
}
};
class CMarker : public CDrawObject
{
CDrawObject* obj;
public:
CMarker(CDrawObject* obj_)
{
obj = obj_;
}
~CMarker()
{
cout << "Delete marker of object with id: " << obj->getId() << endl;
}
CDrawObject* getObject() const
{
return obj;
}
virtual void draw()
{
cout << "CMarker of oject with id: " << obj->getId() << endl;
}
};
int CDrawObject::id = 0;
// predicate for compare objects with int id
class pr : public std::unary_function<CDrawObject*, bool>
{
private:
int id_;
public:
pr(int id): id_(id) {}
bool operator()(CDrawObject* arg) const
{
return (arg->getId() == id_);
}
};
// predicate for check objects with type CMarker and
// compare with CDrawObject* obj
class pr2 : public std::unary_function<CDrawObject*, bool>
{
private:
CDrawObject* obj_;
public:
pr2(CDrawObject* obj)
{
obj_ = obj;
}
bool operator()(CDrawObject* arg) const
{
if (dynamic_cast<CMarker*>(arg))
return ((dynamic_cast<CMarker*>(arg))->getObject() == obj_);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
list<CDrawObject*> m_list;
list<CDrawObject*>::iterator i_list, tmp_list;
m_list.push_back(new CRectangle());
tmp_list = m_list.end();
m_list.push_back(new CMarker(*--tmp_list));
m_list.push_back(new CMarker(*tmp_list));
m_list.push_back(new CRectangle());
tmp_list = m_list.end();
m_list.push_back(new CMarker(*--tmp_list));
m_list.push_back(new CRectangle());
tmp_list = m_list.end();
m_list.push_back(new CMarker(*--tmp_list));
m_list.push_back(new CMarker(*tmp_list));
// print on screen items of m_list
for (i_list = m_list.begin(); i_list != m_list.end(); ++i_list)
(*i_list)->draw();
// get an iterator to the first element in the range with id_ = 2
tmp_list = find_if(m_list.begin(), m_list.end(), pr(2));
if (tmp_list != m_list.end())
{
// remove from list all elements with type CMarker
// and CDrawObject = tmp_list
m_list.remove_if(pr2(*tmp_list));
}
cout << endl << "--------" << endl;
// print on screen items of m_list
for (i_list = m_list.begin(); i_list != m_list.end(); ++i_list)
(*i_list)->draw();
_getch();
return 0;
}
Well you could:
HACKISH: delete the object in the predicate.
ANNOYING: Stay away from remove_if and implement everything it does on your own except add the delete.
BETTER: use RAII objects rather than raw pointers. Some sort of smart ptr in other words.
The way it's implemented at the moment, you won't be able to delete the memory that you allocated for those objects. In general, it takes some extra effort to perform memory cleanup when you have containers of pointers to dynamically allocated memory. Here's one way to do it:
// Assume there's a predicate function called ShouldRemove(int value);
list<int> my_list;
// initialization...
for (list<int>::iterator itr = my_list.begin(); itr != my_list.end(); ) {
if (ShouldRemove(**itr)) {
delete *itr;
itr = my_list.erase(itr);
} else {
++itr;
}
}
But as Noah Roberts pointed out, this is all much easier to deal with if you store your pointers as smart pointers that clean up after themselves.
Standalone remove_if never resizes a collection and returns an iterator pointing to the first object for which predicate is false.
It is therefore more appropriate for your task.