Simple program is written as:
#include <iostream>
#include <vector>
using std::vector;
class Test {
public:
Test( int d ) : data(d), addr(&data) {
}
// Test( Test &src ) : data(src.data), addr(src.addr) { }
const int data;
const int *addr;
~Test() {
delete addr;
}
void print() {
std::cout << " Data is : " << data << '\n';
}
};
int main( int, char**, char** ) {
std::vector<Test> data1;
data1.emplace_back( 98 );
for( auto a : data1 )
a.print();
std::cout << "main";
std::cout << std::endl;
return 0;
}
and the output was
Possibly the reason was the destructor called twice
I tried to get some info from : here and there but cant get clear vison.
As mentioned in comments the problem is the delete statement in destructor which is unwanted for non-dynamic data member.
Related
Maybe it's my sinuses and that I fact that I just started learning about smart pointers today I'm trying to do the following:
Push to the queue
Get the element in the front
Pop the element (I think it will automatically deque once the address out of scope)
Here is the error
main.cpp:50:25: error: cannot convert ‘std::remove_reference&>::type’ {aka ‘std::unique_ptr’} to ‘std::unique_ptr*’ in assignment
50 | inputFrame = std::move(PacketQueue.front());
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
| |
| std::remove_reference<std::unique_ptr<MyObject::Packet>&>::type {aka std::unique_ptr<MyObject::Packet>}
Here is the code
#include <iostream>
#include <memory>
#include <queue>
using namespace std;
class MyObject
{
public:
struct Packet
{
uint8_t message;
uint8_t index;
};
void pushToQueue(void);
void FrontOfQueue(std::unique_ptr<Packet> *inputFrame);
private:
std::queue<std::unique_ptr<Packet>> PacketQueue;
};
void MyObject::pushToQueue(void)
{
Packet frame;
static int counter = 1;
frame.message = counter;
frame.index =counter;
counter++;
std::unique_ptr<Packet> passthru_ptr = std::make_unique<Packet>(std::move(frame));
PacketQueue.push(std::move(passthru_ptr));
cout<<"Pushed to queue\n" ;
}
void MyObject::FrontOfQueue(std::unique_ptr<Packet> *inputFrame)
{
inputFrame = std::move(PacketQueue.front());
}
int main()
{
cout<<"Hello World\n";
MyObject object;
object.pushToQueue();
object.pushToQueue();
{
// Scope
std::unique_ptr<MyObject::Packet> *frame;
object.FrontOfQueue(frame);
cout<< frame << endl;
}
{
// Scope
std::unique_ptr<MyObject::Packet> *frame2;
object.FrontOfQueue(frame2);
cout<< frame2 << endl;
}
return 0;
}
Link to the code (Online Compiler)
If I got your aim correctly, you definitely want
std::unique_ptr<MyObject::Packet> MyObject::FrontOfQueue()
{
auto rv = std::move(PacketQueue.front());
PacketQueue.pop();
return rv;
}
// ...
std::unique_ptr<MyObject::Packet> frame = object.FrontOfQueue();
Notice, no raw pointers are used.
I think it will automatically deque once the address out of scope.
This assumption is wrong. Nothing is dequeued until .pop() is called.
Here is my example with some extra logging to show whats going on.
includes an introduction of returning const references as well.
Live demo : https://onlinegdb.com/P2nFkdMy0
#include <iostream>
#include <memory>
#include <queue>
#include <string>
//-----------------------------------------------------------------------------
// do NOT use : using namespace std;
//-----------------------------------------------------------------------------
struct Packet
{
// moved to uint32_t for std::cout reasons.
// uint8_t is displayed as(special) characters
std::uint32_t index;
std::uint32_t message;
Packet() :
index{ next_index() },
message{ index }
{
std::cout << "created packet : " << index << "\n";
}
~Packet()
{
std::cout << "destroyed packet : " << index << "\n";
}
// small helper to not have to declare the static variable seperatly
static std::uint8_t next_index()
{
static int counter;
return counter++;
}
};
//-----------------------------------------------------------------------------
class MyObject
{
public:
void push_packet();
std::unique_ptr<Packet> pop_packet();
// this function returns a const reference (observation only)
// of the packet at the front of the queue
// while leaving the unique pointer on the queue (no moves needed
// packet will still be owned by the queue)
const Packet& front();
private:
std::queue<std::unique_ptr<Packet>> m_queue;
};
void MyObject::push_packet()
{
std::cout << "push_packet\n";
// push a packet
m_queue.push(std::make_unique<Packet>());
std::cout << "push_packet done...\n";
}
std::unique_ptr<Packet> MyObject::pop_packet()
{
std::unique_ptr<Packet> packet = std::move(m_queue.front());
m_queue.pop();
return packet;
}
const Packet& MyObject::front()
{
return *m_queue.front();
}
//-----------------------------------------------------------------------------
int main()
{
const std::size_t n_packets = 3ul;
MyObject object;
for (std::size_t n = 0; n < n_packets; ++n)
{
std::cout << "pushing packet\n";
object.push_packet();
}
for (std::size_t n = 0; n < n_packets; ++n)
{
std::cout << "packet at front : ";
std::cout << object.front().index << "\n";
std::cout << "popping front\n";
auto packet_ptr = object.pop_packet();
std::cout << "popped packet : " << packet_ptr->index << "\n";
}
return 0;
}
I simplified the code, so pardon my style.
I was wondering what happens to an object that is constructed by a constructor that actually allocates memory, and passed to a lambda by value, when this lambda itself, is being a callback by another thread.
It didn't surprise me to see the program crashes when the destructor is called. This was test#1.
test#2: I removed the "new" and the "delete[]" from c'tor and d'tor of A, and now - it worked fine.
test#3:
I brought the "new" and the "delete[]" back as before, but now I changed every place with "A objA" (by value) into "A& objA", and now, it didn't crash as well.
Now, I can rationalize it by waving my hands but I'd like to understand what really happened here, and for that matter - what would happen if an object that is passed into a lambda by "capture", also ceases to exist.
and last question: is there a good practice or tip what to do (or what to avoid) in such cases?
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
using namespace std::chrono_literals;
class A {
public:
A() : x(1) { ptr = new char[1024]; }
~A() { delete[](ptr); }
int getX() { return x; }
private:
int x = 0;
char* ptr = nullptr;
};
std::function<void(A objA)> myCb;
int myThread()
{
static int counter = 0;
auto a = new A;
while (true) {
std::this_thread::sleep_for(2s);
if (myCb)
myCb(*a);
else
std::cout << "myCb is still NULL: counter = " << counter << std::endl;
if (counter++ == 5)
break;
}
return 0;
}
void registerCallback(std::function<void(A obj)> cb)
{
myCb = cb;
}
int main()
{
std::thread t1(myThread);
std::this_thread::sleep_for(6s);
int val = 5;
registerCallback([&val](A objA) {
std::cout << "here lambda is called with " << objA.getX() << " and " << val << std::endl;
});
val = 6;
std::this_thread::sleep_for(1s);
val = 7;
std::this_thread::sleep_for(1s);
val = 8;
std::this_thread::sleep_for(1s);
t1.join();
}
class A is violating the Rule of 3/5/0, as it does not implement a copy-constructor and/or move-constructor, or a copy-assignment and/or move-assignment operator.
So, when an instance of A is passed around by value, a shallow copy is made that shares the same char* pointer to a single char[] array in memory, and thus the code MAY crash (ie, undefined behavior) when trying to delete[] that same array multiple times.
What you need is a deep copy instead, so that each instance of A allocates its own char[] array, eg:
class A
{
public:
A() : x(1), ptr(new char[1024])
{
std::fill(ptr, ptr + 1024, '\0');
}
A(const A &src) : x(src.x), ptr(new char[1024])
{
std::copy(src.ptr, src.ptr + 1024, ptr);
}
A(A &&src)
: x(src.x), ptr(src.ptr)
{
src.ptr = nullptr;
}
~A()
{
delete[] ptr;
}
A& operator=(A rhs)
{
std::swap(x, rhs.x);
std::swap(ptr, rhs.ptr);
return *this;
}
int getX() const { return x; }
private:
int x;
char* ptr;
};
A simpler way to implement this is to use std::vector instead of new[], since vector is already compliant with the Rule of 3/5/0, and so compiler-generated constructors, destructor, and assignment operators for A will suffice to make copies/moves of the vector for you, eg:
#include <vector>
class A
{
public:
A() : vec(1024, '\0') {}
int getX() const { return x; }
private:
int x = 1;
std::vector<char> vec;
};
You should use unique_ptr. deleting a void* is undefined behavior
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
using namespace std::chrono_literals;
class A {
public:
A() : x(1)
{
ptr = std::make_unique<char[]>(1024);
}
~A()
{
}
int getX() { return x; }
private:
int x = 0;
std::unique_ptr<char[]> ptr = nullptr;
};
std::function<void(A& objA)> myCb;
int myThread()
{
static int counter = 0;
auto a = new A;
while (true) {
std::this_thread::sleep_for(2s);
if (myCb)
myCb(*a);
else
std::cout << "myCb is still NULL: counter = " << counter << std::endl;
if (counter++ == 5)
break;
}
return 0;
}
void registerCallback(std::function<void(A& obj)> cb)
{
myCb = cb;
}
int mymain()
{
std::thread t1(myThread);
std::this_thread::sleep_for(6s);
int val = 5;
registerCallback([&val](A& objA) {
std::cout << "here lambda is called with " << objA.getX() << " and " << val << std::endl;
});
val = 6;
std::this_thread::sleep_for(1s);
val = 7;
std::this_thread::sleep_for(1s);
val = 8;
std::this_thread::sleep_for(1s);
t1.join();
return 0;
}
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.
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
I'm coding a simple c++ factory and I get an error that I don't understand.
This is my class definition:
MSGFactory.hpp
class MSGFactory
{
public:
static MSGFactory * getInstance();
void registerMSG(const std::string MSGType , createMSGFn constructor );
MSGData *createMessage(const std::string &MSGType);
private:
static MSGFactory * inst;
std::map<std::string,createMSGFn> MSGPool;
};
and this is its implementation:
MSGFactory.cpp
MSGFactory * MSGFactory::getInstance()
{
if(inst == NULL) inst = new MSGFactory();
return inst;
}
void MSGFactory::registerMSG(const std::string MSGType , createMSGFn constructor )
{
MSGPool.insert(factoryBucket(MSGType,constructor));
}
MSGData * MSGFactory::createMessage(const std::string &MSGType)
{
std::map<std::string,createMSGFn>::iterator it;
it = MSGPool.find(MSGType);
if( it != MSGPool.end() )
return it->second();
return NULL;
}
I wrote this test program:
T_MSGFactory.cpp
class MSGOne : MSGData
{
public:
MSGOne(){}
~MSGOne() {{std::cout<<"Derived destructor called\n";}}
std::string type() { std::cout << "Type One" << std::endl; return " ";}
unsigned char* getData(){ return (unsigned char *) "a"; }
static MSGData * Create() { return new MSGOne(); }
};
class MSGTwo : MSGData
{
public:
MSGTwo(){}
~MSGTwo() {std::cout<<"Derived destructor called\n";}
std::string type() { std::cout << "Type Two" << std::endl; return " ";}
unsigned char* getData(){ return (unsigned char *) "a"; }
static MSGData * Create() { return new MSGTwo(); }
};
class MSGThree : MSGData
{
public:
MSGThree(){}
~MSGThree() {std::cout<<"Derived destructor called\n";}
std::string type() { std::cout << "Type Three" << std::endl; return " ";}
unsigned char* getData(){ return (unsigned char *) "a"; }
static MSGData * Create() { return new MSGThree(); }
};
int main(int argc, char **argv)
{
std::cout << "PROVA" << std::endl;
MSGFactory::getInstance()->registerMSG("ONE", &MSGOne::Create );
MSGFactory::getInstance()->registerMSG("TWO", &MSGTwo::Create );
MSGFactory::getInstance()->registerMSG("THREE", &MSGThree::Create );
return 0;
}
but compiling it with "g++ T_MSGFactory.cpp MSGFactory.cpp" I get this error:
1) "riferimento non definito a" is "undefined reference to"
2) "nella funzione" is "in function"
Can someone help me? Thanks
In the top of your MSGFactory.cpp file, just after the includes, in the global scope, you should declare the static member.
like this:
MSGFactory* MSGFactory::inst=NULL;
Static member variables must be defined, usually in the source file.
Add this to your MSGFactory.cpp
MSGFactory* MSGFactory::inst = 0;
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/