Free memory after remove_if - c++

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.

Related

Is it possible to use std::make_unique in a class constructor and `this` pointer?

I am trying to use unique_ptr instead of raw pointers for components that are assigned to an actor class.
#include <iostream>
#include <memory>
#include <utility>
#include <algorithm>
#include <vector>
class Component;
class Actor
{
public:
void AddComponent(std::unique_ptr<Component> component)
{
std::cout << "Add component\n";
mComponents.push_back(std::move(component));
}
void RemoveComponent(Component* component)
{
std::cout << "Removing Component...\n";
auto iter = std::find_if(mComponents.begin(), mComponents.end(),[&](const auto& e){ return e.get() == component;});
if(iter != mComponents.end())
{
mComponents.erase(iter);
std::cout << "Removed from vector \n";
}
}
void ListComponents()
{
for(const auto& element : mComponents)
{
std::cout << "Component:" << element.get() << "\n";
}
}
private:
std::vector<std::unique_ptr<Component> > mComponents;
};
class Component
{
public:
Component(Actor* actor) : mOwner(actor) {actor->AddComponent(std::make_unique<Component>(*this));}
virtual ~Component() { std::cout << this << ":Destroyed \n"; }
private:
Actor* mOwner = nullptr;
};
int main(int argc, char* argv[])
{
Actor Actor1;
auto c1 = Component(&Actor1);
auto c2 = Component(&Actor1);
Actor1.ListComponents();
}
Is there a way to assign the this pointer to a unique_ptr, or am I right that I need to use a factory function of some kind?
Thanks!
EDIT: Corrected Code:
#include <iostream>
#include <memory>
#include <utility>
#include <algorithm>
#include <vector>
class Component;
class Actor
{
public:
void AddComponent(std::unique_ptr<Component> component)
{
std::cout << "Add component\n";
mComponents.push_back(std::move(component));
}
void RemoveComponent(Component* component)
{
std::cout << "Removing Component...\n";
auto iter = std::find_if(mComponents.begin(), mComponents.end(),[&](const auto& e){ return e.get() == component;});
if(iter != mComponents.end())
{
mComponents.erase(iter);
std::cout << "Removed from vector \n";
}
}
void ListComponents()
{
for(const auto& element : mComponents)
{
std::cout << "Component:" << element.get() << "\n";
}
}
private:
std::vector<std::unique_ptr<Component> > mComponents;
};
class Component
{
public:
Component(Actor* actor) : mOwner(actor) {actor->AddComponent(std::unique_ptr<Component>(this));}
virtual ~Component() { std::cout << this << ":Destroyed \n"; }
private:
Actor* mOwner = nullptr;
};
int main(int argc, char* argv[])
{
Actor Actor1;
auto c1 = new Component(&Actor1);
auto c2 = new Component(&Actor1);
Actor1.ListComponents();
}
There are at least three issues here.
There are various syntax errors (missing declaration of Component before the definition of Actor, typos, ... I'll ignore them now they are mentionned.
The if you have any pointer, you can build a unique_ptr from it which will handle the lifetime of the object. That's not made with make_unique but with the constructor:
owner->AddComponent(std::unique_ptr<Component>(this));
You can do that but the unique_pointer will manage the lifetime of the Component. So that means that nothing else should and you have to avoid that, especially temporaries and stack allocated one. So you'll have to replace:
c1 = Component(&Actor1);
c2 = Component(&Actor1);
by something like:
new Component(&Actor1);
new Component(&Actor1);
There are various way to enforce that so that mistakes are detected at compilation, but I'll not go into them.

How to insert to std::map in C++11?

I am trying to insert a set of pair values into a std::map in c++11. However, the values don't seem to insert into the std::map. Please do go over my code about the same. I appreciate any and all help.
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<cstdlib>
#include<utility>
#include<ctime>
#include "print.h"
class ReportCard
{
private:
std::map<std::string, double> m_report_card;
public:
std::map<std::string, double> getReportCardInstance() { return m_report_card; }
};
class Student
{
private:
int m_roll_no;
std::string m_name;
ReportCard m_reportCard;
public:
Student(int inRollNo, const std::string& inName) :
m_roll_no(inRollNo), m_name(inName)
{}
std::string getName() { return m_name; }
int getRollNo() { return m_roll_no; }
ReportCard getReportCard() { return self.m_reportCard; }
int getReportCardSize() { return m_reportCard.getReportCardInstance().size(); }
};
class Driver
{
private:
std::vector<Student> student_list;
std::vector<Student> temp;
public:
void studentTestPopulate()
{
student_list.push_back(Student(1, "Tim"));
student_list.push_back(Student(2, "Matt"));
student_list.push_back(Student(100, "Luke"));
student_list.push_back(Student(68, "Lissy"));
student_list.push_back(Student(20, "Tony"));
student_list.push_back(Student(33, "Joseph"));
student_list.push_back(Student(14, "Sid"));
student_list.push_back(Student(15, "Roby"));
student_list.push_back(Student(44, "Rohan"));
student_list.push_back(Student(11, "Kevin"));
student_list.push_back(Student(19, "George"));
}
void reportCardPopulate()
{
for (auto& student : student_list)
{
std::cout << student.getName() << std::endl;
student.getReportCard().getReportCardInstance().insert(std::make_pair<std::string, double>("Math", generateMark));
//This is the function that does not work. No marks are printed!!
for (auto& mark : student.getReportCard().getReportCardInstance())
{
std::cout << mark.first << " " << mark.second;
}
//student.getReportCard().getReportCardInstance().insert(std::make_pair("Science", generateMark));
//student.getReportCard().getReportCardInstance().insert(std::make_pair("Geography", generateMark));
//student.getReportCard().getReportCardInstance().insert(std::make_pair("French", generateMark));
//student.getReportCard().getReportCardInstance().insert(std::make_pair("History", generateMark));
}
}
void showAllStudentDetails()
{
for (auto& student : student_list)
{
std::cout << student.getName() << std::endl;
std::cout << student.getRollNo() << std::endl;
std::cout << "REPORT CARD : " << student.getReportCardSize() << std::endl << std::endl;
for (auto& mark : student.getReportCard().getReportCardInstance())
{
std::cout << mark.first << std::endl;
std::cout << mark.second << std::endl;
}
}
}
};
int main()
{
srand(time(NULL));
Driver driver;
driver.studentTestPopulate();
driver.reportCardPopulate();
//driver.showAllStudentDetails();
}
The reportCardPopulate() function is supposed to insert pairs of values into a report_card map. However, the insert function doesn't seem to work.
When we try to print the values within the reportCardPopulate() function, it doesn't print anything. When I try to print the size of the map, it prints 0. When I printed the size using sizeof() it prints the same size before and after the insertion.
The following functions
std::map<std::string, double> getReportCardInstance() { ... }
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ReportCard getReportCard() { ... }
//^^^^^^^^
returns the copy of std::map<std::string, double> and ReportCard class respectively. Therefore, whatever you insert here
student.getReportCard().getReportCardInstance().insert(std::make_pair<std::string, double>("Math", generateMark));
does on the copies of the above, hence the original member in ReportCard(i.e. m_report_card) will never get be updated. After the call of above line, the copies will be destroyed and expecting it to work make no sense.
Secondly, shown code is wrong, because in c++ you should have used this not self
ReportCard getReportCard()
{
return self.m_reportCard;
//^^^^ --> should be `return this->m_reportCard;`
// or simply `return m_reportCard;`
}
Correcting the above, and returning the member by reference will make the code work.
(See live online)
std::map<std::string, double>& getReportCardInstance()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
return m_report_card;
}
ReportCard& getReportCard()
//^^^^^^^^
{
return m_reportCard;
}
That being said, your ReportCard and Student classes will expose the members, if you do the above. Which is not a good design. If those are meant only for the internal uses of Driver class, you could keep them as private properties of Driver class.
#include <vector>
#include <map>
#include <string>
#include <iostream>
class Driver /* final */ // -> optional
{
private: // Student is private for Driver class
class Student
{
// type alias is enough for the map
using ReportCard = std::map<std::string, double>;
private:
int m_roll_no;
std::string m_name;
ReportCard m_reportCard;
public:
Student(int inRollNo, const std::string& inName)
: m_roll_no{ inRollNo }, m_name{ inName }
{}
// make the member functions const if they are not modifing the members
const std::string& getName() const { return m_name; }
int getRollNo() const { return m_roll_no; }
ReportCard& getReportCard() { return m_reportCard; }
std::size_t getReportCardSize() const { return m_reportCard.size(); }
};
private:
std::vector<Student> student_list;
std::vector<Student> temp;
public:
void studentTestPopulate()
{
// construct the `Student` in-place using `std::vector::emplace_back`
student_list.emplace_back(1, "Tim");
student_list.emplace_back(2, "Matt");
student_list.emplace_back(100, "Luke");
student_list.emplace_back(68, "Lissy");
student_list.emplace_back(20, "Tony");
student_list.emplace_back(33, "Joseph");
student_list.emplace_back(14, "Sid");
student_list.emplace_back(15, "Roby");
student_list.emplace_back(44, "Rohan");
student_list.emplace_back(11, "Kevin");
student_list.emplace_back(19, "George");
}
void reportCardPopulate()
{
for (auto& student : student_list)
{
std::cout << student.getName() << "\n";
student.getReportCard().emplace(student.getName(), 12.0);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// use `std::map::emplace` for constructing `ReportCard` in-place
for (auto& mark : student.getReportCard())
{
std::cout << mark.first << " " << mark.second << "\n";
}
}
}
// ... other members
};
int main()
{
Driver driver;
driver.studentTestPopulate();
driver.reportCardPopulate();
}
#include <iostream>
#include <map>
class ReportCard
{
//private: this is the default anyway for a class
public: //made to be able to print the internals below.
std::map<std::string, double> m_report_card;
public:
/* this returns an instance of the std::map. The map is copied and
returned, so any modifications will not affect m_report_card
std::map<std::string, double> getReportCardInstance()
{
return m_report_card;
}
if you want to do this, return std::map<std::string, double>&.
std::map<std::string, double>& getReportCardInstance()
{
return m_report_card;
}
*/
// better solution is to have a method to add the report
void add_report(const std::string& first,double second)
{
m_report_card[first] = second;
}
};
int main() {
ReportCard rc;
rc.add_report("Percy",1.0);
rc.add_report("Pig",2.0);
for(auto internal_report_card : rc.m_report_card)
{
std::cout << internal_report_card.first << ", "
<< internal_report_card.second << std::endl;
}
return 0;
}
Demo

Make a collection of an abstract class type, Abstract Class vector of shared_ptr

Error
e/c++/v1/algorithm:642:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/utility:321:9: error:
field type 'Space' is an abstract class
_T2 second;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/map:624:16: note:
Question
How can I define a std::vector of type Space which is an abstract class and then fill this vector with instances of the derived classes Empty, Snake, Ladder.
Context
I know abstract classes in C++ can not be instantiated. Instead I've read in several posts on this and other sites that you can create a collection of an abstract type if it the type is defined as a star * pointer or any of the <memory> managed pointer data types like std::unqiue_ptr<T>. I've tried to used shared_ptr<Space> in my case, but still unable to define the collection properly. I am compiled my code using g++ -std=c++17 main.cpp && ./a.out.
Code
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <map>
#include <memory>
#include <typeinfo>
#include <queue>
#include <string>
#include <vector>
class Player
{
private:
int m_current_space = 1;
public:
Player() {}
void role_dice() {
m_current_space += floor( (rand()%10 + 1) / 3 );
}
int const get_current_space() {
return m_current_space;
}
void set_current_space(int current_space) {
m_current_space = current_space;
}
};
class Space
{
protected:
int m_id;
std::vector<Space> m_paths;
public:
Space() {} // requied to use [] operator in map
Space(int id) : m_id(id) {}
void add_path(Space& s) {
m_paths.push_back(s);
}
int get_id() {
return m_id;
}
virtual std::string class_type() = 0;
};
class Empty : public Space
{
public:
Empty(int id) : Space(id) {}
std::string class_type() {
return "Empty";
}
};
class Ladder : public Space
{
public:
Ladder(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(1);
}
std::string class_type() {
return "Ladder";
}
};
class Snake : public Space
{
public:
Snake(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(4);
}
std::string class_type() {
return "Snake";
}
};
class Board
{
private:
std::map<int, Space> m_board;
public:
void add_space(Space& s) {
m_board[s.get_id()] = s;
}
void draw_board() {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
std::cout << "○\n";
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
std::cout << "○ ";
}
++i;
}
}
void update_player_on_board(int position) {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
if (space_key == position) {
std::cout << "●\n";
}
else {
std::cout << "○\n";
}
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
if (space_key == position) {
std::cout << "● ";
}
else {
std::cout << "○ ";
}
}
++i;
}
}
const std::map<int, Space> get_board() {
return m_board;
}
friend std::ostream &operator<<(std::ostream& os, const Board& b) {
return os;
}
};
class GameStateManager
{
private:
std::string m_state = "game over";
bool m_playing = false;
public:
std::string const get_state() {
return m_state;
}
void set_state(std::string state) {
m_state = state;
}
};
int main()
{
std::cout << "Welcome to Bowser's 9 board game\n";
std::cout << "Start? y(yes) n(no)\n";
GameStateManager game_manager;
game_manager.set_state("playing");
auto space1 = std::make_shared<Space>(1);
auto space2 = std::make_shared<Space>(2);
auto space3 = std::make_shared<Space>(3);
auto space4 = std::make_shared<Space>(4);
auto space5 = std::make_shared<Space>(5);
auto space6 = std::make_shared<Space>(6);
auto space7 = std::make_shared<Space>(7);
auto space8 = std::make_shared<Space>(8);
auto space9 = std::make_shared<Space>(9);
std::vector<std::shared_ptr<Space>> v {
space1, space2, space3,
space4, space5, space6,
space7, space8, space9
};
Board bowsers_bigbad_laddersnake;
for(int i = 0; i < 10; ++i) {
bowsers_bigbad_laddersnake.add_space(*(v[i]));
}
bowsers_bigbad_laddersnake.draw_board();
Player mario;
int turn = 0;
while(game_manager.get_state() == "playing") {
std::cin.get();
std::cout << "-- Turn " << ++turn << " --" << '\n';
mario.role_dice();
bowsers_bigbad_laddersnake.update_player_on_board(mario.get_current_space());
if (mario.get_current_space() >= 9) {
game_manager.set_state("game over");
}
}
std::cout << "Thanks a so much for to playing!\nPress any key to continue . . .\n";
std::cin.get();
return 0;
}
You seem to have removed a lot of code to get into details here.
Have a Space pointer (smart or raw). Instantiate the specific space that you want, point to it with your pointer of type Space. Example std::shared_ptr<Space> pointerToSpace = std::make_shared<Snake> ("I'm a snake"); Now, without loss of generality, you can print the contents (of concrete type) with just the pointer to the space pointerToSpace->class_type(). Yes, you can have a collection of shared_ptrs in a container.

Good way to create observer design pattern in C++

I am trying to implement observer design pattern in C++ as below
#include <iostream>
#include <vector>
using namespace std;
class observer
{
public:
observer() = default;
~observer() = default;
virtual void notify() = 0;
};
class subject
{
vector <observer *> vec;
public:
subject() = default;
~subject() = default;
void _register(observer *obj)
{
vec.push_back(obj);
}
void unregister(observer *obj)
{
int i;
for(i = 0; i < vec.size(); i++)
{
if(vec[i] == obj)
{
cout << "found elem. unregistering" << endl;
vec.erase(vec.begin() + i);
break;
}
}
if(i == vec.size())
{
cout << "elem not found to unregister" << endl;
}
}
void notify()
{
vector <observer *>::iterator it = vec.begin();
while(it != vec.end())
{
(*it)->notify();
it ++;
}
}
};
class obsone : public observer
{
void notify()
{
cout << "in obsone notify" << endl;
}
};
class obstwo : public observer
{
void notify()
{
cout << "in obstwo notify" << endl;
}
};
int main()
{
subject sub;
obsone *one = new obsone();
obstwo *two = new obstwo();
sub._register(one);
sub._register(two);
sub.notify();
sub.unregister(one);
sub.notify();
//delete two;
//sub.notify();
return 0;
}
I am registering the objects with the subject explicitly. Is it the correct way of doing it or do I need to register through observer class only. Are there any problems with the above approach?
Here's an example of doing the callbacks with lambdas and function objects in the callback collection.
The details can vary greatly! So, this code is not “the” way, but just your code rewritten in one specific way, out of a myriad possibilities. But it hopefully shows the general idea in modern C++.
#include <iostream>
#include <functional> // std::function
#include <stdint.h> // uint64_t
#include <unordered_map> // std::unordered_map
#include <utility> // std::move
#include <vector> // std::vector
using namespace std;
namespace my
{
using Callback = function<void()>;
template< class Key, class Value > using Map_ = unordered_map<Key, Value>;
class Subject
{
public:
enum Id: uint64_t {};
private:
Map_<uint64_t, Callback> m_callbacks;
static auto id_value()
-> uint64_t&
{
static uint64_t the_id;
return the_id;
}
public:
auto add_listener( Callback cb )
-> Id
{
const auto id = Id( ++id_value() );
m_callbacks.emplace( id, move( cb ) );
return id;
}
auto remove_listener( const Id id )
-> bool
{
const auto it = m_callbacks.find( id );
if( it == m_callbacks.end() )
{
return false;
}
m_callbacks.erase( it );
return true;
}
void notify_all() const
{
for( const auto& pair : m_callbacks )
{
pair.second();
}
}
};
}
struct Observer_1
{
void notify() { cout << "Observer_1::notify() called." << endl; }
};
struct Observer_2
{
void notify() { cout << "Observer_2::notify() called." << endl; }
};
auto main()
-> int
{
my::Subject subject;
Observer_1 one;
Observer_2 two;
using Id = my::Subject::Id;
const Id listener_id_1 = subject.add_listener( [&]{ one.notify(); } );
const Id listener_id_2 = subject.add_listener( [&]{ two.notify(); } );
cout << "After adding two listeners:" << endl;
subject.notify_all();
cout << endl;
subject.remove_listener( listener_id_1 )
and (cout << "Removed listener 1." << endl)
or (cout << "Did not find registration of listener 1." << endl);
cout << endl;
cout << "After removing or attempting to remove listener 1:" << endl;
subject.notify_all();
}

getting error on vector<unique_ptr<X>> v

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.