Using: CodeBlocks 13.12, GNU GCC mingw32-g++, Dr.Memory
So I have an assignment to make a vector queue (first in first out).
I made the program and everything worked fine, but in the assignment we need to use an interface IQueue. This interface can not be changed.
#ifndef IQUEUE_H
#define IQUEUE_H
template <typename T>
class IQueue {
public:
virtual void enqueue(const T& element) = 0;
virtual T dequeue() = 0;
virtual T front() const = 0;
virtual bool isEmpty() const = 0;
};
#endif
This is (some) of my Queue.h just so you get the picture.
#ifndef QUEUE_H
#define QUEUE_H
#include <iostream>
#include <string>
#include <stdexcept>
#include "iqueue.h"
using namespace std;
template <typename T>
class Queue : virtual public IQueue<T> {
public:
Queue();
Queue(int capacity);
Queue(int capacity, int capacity_increment);
~Queue();
Queue(const Queue<T> &original);
void operator=(const Queue<T> &original);
void enqueue(const T& element);
T dequeue();
T front() const;
bool isEmpty() const;
private:
T *items;
int nr_of_items;
int capacity;
void expand(); //expands the array if the nr_of_items is bigger than capacity
void freeMemory();
};
/*stuff*/
template<typename T>
Queue<T>::~Queue() {
this->freeMemory();
}
template<typename T>
void Queue<T>::freeMemory() {
delete[] this->items;
}
I'm using freeMemory() in the operator= that's why it's a separate function.
So now to the main
#include "iqueue.h"
#include "queue.h"
int main() {
IQueue<string> *sq = new Queue<string>();
/*Do stuff with the queue*/
IQueue<string> *sq2 = new Queue<string>();
sq2 = sq;
IQueue<int> *iq = new Queue<int>();
/*Do stuff with the queue*/
IQueue<int> *iq2 = new Queue<int>();
iq2 = iq;
/*how to delete?*/
return 0;
}
Things I've tested:
delete sq;delete sq2;delete iq; delete iq2; with cout in freeMemory() it doesn't run at all.
Same as before but I tested making a virtual deconstructor in the IQueue. with cout in freeMemory() it runs once and then crashes. I get 4 unaddressable accesses, 2 invalid heap argument, 2 memory leaks.
Don't really get what happens here.
We haven't used uniqe pointers yet but when I googled around that was suggested as a good method. But I would need a good explanation for my program to know how to do that.
Tried vector::erase cplusplus.com link.
Feels like this is the right way to go, however I just get errors about "vector erase used without template class". I've included < vector >.
Any answer that can point me in the right direction is appreciated. General info about why the things I tried didn't work would be nice and give me better understanding.
I'll edit more code in if needed.
Sidenote: We were told you put throw(...) in the .h file if there should be a try catch exception in the function like this:
virtual T dequeue()throw(…) = 0;
But I just got errors, is this a standard way of doing it?
IQueue<string> *sq = new Queue<string>();
IQueue<string> *sq2 = new Queue<string>();
sq2 = sq;
First memory leak. You lose pointer to sq2 object.
IQueue<int> *iq = new Queue<int>();
IQueue<int> *iq2 = new Queue<int>();
iq2 = iq;
Second memory leak. Same as above.
Now if you delete pointer to iq1 or iq2 you will have third leak because your interface has no virtual destructor so destructor in your implementation will not be called.
Things that I have noticed fron your code and points are:
1) You are working with pointers. That is, you are actually assigning one pointer to the other. So, operator=() will not be invoked. And memory will leak there.
2) As you said in your first point, you are deleting sq and then sq2, both of which were pointing to the same memory. Thus heap corruption was detected. Same is happenning with iq and iq2.
3) Also use virtual destructor.
Related
Why this can't work. Is there any way to do this?
I don't want to create a separate function for pointers
#include <iostream>
using namespace std;
template<class T>
class temp
{
public:
T val;
temp(T value) : val(value) {}
~temp()
{
if(is_pointer<T>::value)
{
delete val;
}
}
};
int main()
{
string * n = new string("cat");
temp<string*>object(n);//ok
temp<string>object2("dog"); //compliation error: type 'class std::cxx11::basic_string' argument given to 'delete', expected pointer. --- (but there is if statement!!!!)
//i dont want delete in main
return 0;
}
To compile i use g++ 6.3.0
Could someone help? Maybe, I need to separate declaration from definition?
The issue that you have is that the branch of an if must always be syntactically valid, even if it is never taken.
You could do it with if constexpr, which is a "compile time if"
~temp()
{
if constexpr(is_pointer<T>::value)
{
delete val;
}
}
However this isn't safe.
How do you know that the pointer passed to temp<T*> was created by new and not new[], malloc, or by taking the address of an object that wasn't dynamically allocated?
Rather than assume that pointers should be deleted, you should avoid having to know which pointers to delete
#include <string>
#include <memory>
template<class T>
class temp
{
public:
T val;
temp(T value) : val(value) {}
// n.b. no need to define destructor
};
int main()
{
std::string str("cat");
temp<std::string*> object(&str);//ok
temp<std::string> object2("dog"); // also ok
std::unique_ptr<std::string> str2 = std::make_unique<std::string>("mouse");
temp<std::string *> object3(str2.get()); // ok so long as str2 outlives object3
std::shared_ptr<std::string> str3 = std::make_shared<std::string>("rabbit");
temp<std::shared_ptr<std::string>> object4(str3); // also ok
return 0;
}
SO I am trying to teach myself data structures in C++. To do so, I made an ArrayList class with a member variable arrayData with type int* and a get method to access values from that pointer. I come from a Java background and C++ OOP is sorta strange, especially with the separation of header and source files. At compile, I get, "error: 'int* ArrayList::arrayData' is not a static data member of 'class ArrayList'". I marked them with ArrayList:: to make them members of ArrayList, so why does this not mark them as such? Thank you so much if you can point me in the direction of how to access my variable.
ArrayList.cpp:
#include "ArrayList.h"
ArrayList::ArrayList(int size) {
arrayData = new int[size];
}
ArrayList::~ArrayList() {
delete arrayData;
}
int* ArrayList::get(int index) {
return (*(this.arrayData))[index];
}
int* ArrayList::arrayData;
ArrayList.h:
#define ARRAYLIST_H_
class ArrayList {
public:
ArrayList(int size);
~ArrayList();
int get(int index);
private:
int* arrayData;
};
#endif /* ARRAYLIST_H_ */
This line:
int* ArrayList::arrayData;
In the source file makes no sense. Compiler thinks you're referencing a static variable of ArrayList (because you've prepended with the class name). Remove this line.
You will be able to access arrayData from the other methods.
Also, use std::unique_ptr<int> instead of the raw pointer. Then your memory is guaranteed to be automatically released after use.
You have a few errors here.
First, your ArrayList.h include guards are incorrect.
#ifndef ARRAYLIST_H_
#define ARRAYLIST_H_
class ArrayList {
public:
ArrayList(int size);
~ArrayList();
int get(int index);
private:
int* arrayData;
};
#endif /* ARRAYLIST_H_ */
Next, Your int ArrayList::get declaration and definition are inconsistent. There isn't a need for the int* ArrayList::arrayData; in your C++ file as well.
#include "ArrayList.h"
ArrayList::ArrayList(int size) {
arrayData = new int[size];
}
ArrayList::~ArrayList() {
delete arrayData;
}
int ArrayList::get(int index) {
return arrayData[index];
}
I am searching for a long time on net. But no use. Please help or try to give some ideas:
I found a reproductive error in template class when I tried to alloc more space for a dynamic array member managed by a pointer with a friend function. If I turn to another member function, or just in the Push(), to finish this process, error vanished.
Independent from private/public accessibility, Error cover all field of array member accession, once I tried to read or delete element in it, error happend.
No clear tips were given by GCC compiler. Error didn't affect basic types, like int.
Binding friend & Unbinding friend both suffer from this error
Is there anything wrong in my code, or there is some limitation I didn't know in using memory function?
Every opinion, link and anwser is appreciated.
PS: To make posted code more clearly, I simplify some unimportant code. But to provide enough imformation, it still looks so long, feel sorry to the
reading difficulty.
PS2:Guarantee can be made that code simplified is correct.
Error occurs both in Debug mode(x64 and x86),Visual Studio 2017
and cmake 3.13.4-GCC 7.2.0 toolchain debugging with gdb in VScode.
//Bizcard.hpp
class Bizcard
{
private:
char *name;
char *phone;
public:
Bizcard();
Bizcard(const char* n,const char* phone);//constructor
Bizcard(const Bizcard &b);//copy constructor
Bizcard& operator=(const Bizcard& b);//assignment operator
~Bizcard();
};
//Bizcard.cpp
#include"Bizcard.hpp"
#include<string.h>
#include<iostream>
Bizcard::Bizcard()
{
name = nullptr;
phone = nullptr;
}
Bizcard::Bizcard(const char* n ,const char* p)
{
//simplified...
}
Bizcard::Bizcard(const Bizcard &b)
{
//simplified...
}
Bizcard& Bizcard::operator=(const Bizcard& b)
{
if(this==&b)
return *this;
delete[] this->name;//Error would occur here if using
//friend func to expand array capacity
delete[] this->phone;
if(b.name==nullptr)
{
name = nullptr;
phone = nullptr;
return *this;
}
int nlen = strlen(b.name);
int plen = strlen(b.phone);
this->name = new char[nlen+1];
strcpy_s(name, nlen + 1, b.name);
this->phone = new char[plen+1];
strcpy_s(phone, plen + 1, b.phone);
return *this;
}
Bizcard::~Bizcard()
{
delete[] name;
delete[] phone;
}
//BagTemplate.hpp
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include"Bizcard.hpp"
template<typename Type>
void ChangeSize1D_binding(Type* array, int old_capacity, int new_capacity)
{
if(new_capacity<old_capacity)
throw "Paragram Error! New capacity must greater than the old one.";
Type* temp_array =new Type[new_capacity];
std::copy(array,array+old_capacity,temp_array);
delete[] array;
array = temp_array;//Point array to the dest of temp_array
}
template<typename T>
class Bag
{
public:
Bag(int bagCapability =3);
~Bag();
void Push(const T&);
void ChangeSize1D_self(int old_capacity, int new_capacity);
private:
T *array;
int capacity;
int top;
friend void ChangeSize1D_binding<T>(T* array, int old_capacity, int new_capacity);
template<typename Type>
friend void ChangeSize1D_unbind(Type* array, int old_capacity, int new_capacity);
};
template<typename T>
Bag<T>::Bag(int bagCapacity):capacity(bagCapacity)
{
if(capacity<1) throw "Capacity must be >0";
array = new T[capacity];
top = -1;
}
template<typename T>
Bag<T>::~Bag()
{
delete[] array;
}
template<typename T>
void Bag<T>::ChangeSize1D_self(int old_capacity,int new_capacity)
{
if(new_capacity<old_capacity)
throw "Paragram Error! New capacity must greater than the old one.";
T* temp_array =new T[new_capacity];
std::copy(array,array+old_capacity,temp_array);
delete[] array;
array = temp_array;
}
template<typename Type>
void ChangeSize1D_unbind(Type* array, int old_capacity, int new_capacity)
{
if(new_capacity<old_capacity)
throw "Paragram Error! New capacity must greater than the old one.";
Type* temp_array =new Type[new_capacity];
std::copy(array,array+old_capacity,temp_array);
delete[] array;
array = temp_array;
}
template<typename T>
void Bag<T>::Push(const T& x)
{
if(capacity ==top+1)
{
//this->ChangeSize1D_self(capacity,2*capacity);
ChangeSize1D_unbind(array,capacity, 2*capacity);
//ChangeSize1D_binding(array,capacity, 2*capacity);
/*T* temp_array = new T[2 * capacity];
std::copy(array,array+capacity,temp_array);
delete[] array;
array = temp_array;*/
capacity*=2;
}
array[++top]=x;
}
//main.cpp
int main()
{
Bag<int> IntBag;
IntBag.Push(1);
IntBag.Push(1);
IntBag.Push(1);
IntBag.Push(1);
Bag<Bizcard> BizcardBag;
BizcardBag.Push(Bizcard());
BizcardBag.Push(Bizcard());
BizcardBag.Push(Bizcard());
BizcardBag.Push(Bizcard());//Error may happen here since Push() it need
//expanding capacity(origin value: 3)
/*1.as predict, Push success if change size process is directly in Push()
2.when turn to ChangeSize1D(), same error occur
2.1 when change to private member func, no error
2.2 when change to public member func, no error
2.3 when change to private unbinding friend func, same error occur;means private or public doesnt effect behaviour
2.4 when change to private binding friend func, same error occur
*/
return EXIT_SUCCESS;
}
#CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(BugReproduct)
include_directories("${PROJECT_SOURCE_DIR}/Bizcard")
add_subdirectory("${PROJECT_SOURCE_DIR}/Bizcard")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED true)
add_executable(BugReproduct ArrayExpansion.cpp)
target_link_libraries(BugReproduct Bizcard)
#Bizcard/CMakeList.txt
add_library(Bizcard Bizcard.cpp)
Problem SOLVED, this error happened because I pass the pointer directly to friend func, thus friend func would hold a copy but not reference or pointer to it. When I changed the destination the copied "array" pointed to in friend func, which changed the address value it saved, such process do nothing to the real array pointer outside, leading to error when I access the extra alloc element.
This issue can be another footnote about how dangerous pointer is and how much effort should be made before using pointer prefectly.
Profound appreciate to all the help you ever gave. Thank you all.
I am a C++ newbie and I need help with a strange issue (or at least its strange to me)
I have a class as such:
class Myclass {
private:
int A;
// some other stuff...
public:
// constructor and stuff...
void setA(int a);
int* getA_addr();
};
void Myclass::setA(int a){
A = a;
};
int* Myclass::getA_addr(){
return &A;
};
Now, I want to modify A in main() and I am not using any other methods in the class (I did it by using extra methods and now I want to see how I can do it without using those extras). I have a function as such:
void change(int *ptr, int tmp){
*ptr = tmp;
};
In a call to this function, I do the passing as such: change(obj.getA_addr(), other arguments...) where obj is an instance of Myclass.
When done in this way, I receive no compilation errors but I also can't seem to modify A (of obj). As a debug effort, I tried to print the address of A (of obj) by directly calling getA_addr(). I saw that with every call, the function returns a different address. So I am assuming that I am not passing the intended address into the function.
I have no idea why this is happening and would like to know. Also, the way I'm trying to do this is most likely not at all accurate so please, if you can provide a solution, it would be appreciated. Thanks.
EDIT: Here's the most minimal code I could come up with that reproduces the error
#include <iostream>
#define MAX_SIZE 10
using namespace std;
class Student {
private:
int mt1;
public:
Student();
void setMt1(int in_mt1);
int* getMt1();
};
Student::Student() {};
void Student::setMt1(int in_mt1) { mt1 = in_mt1; };
int* Student::getMt1(){ return &mt1; };
class Course {
private:
Student entries[MAX_SIZE];
int num;
public:
Course();
void addStudent(Student in_student);
Student getStudent(int index);
};
Course::Course(){ num = 0; };
void Course::addStudent(Student in_student){
entries[num] = in_student;
num++;
};
Student Course::getStudent(int index){ return entries[index]; };
int main() {
void updateStudentScore(int *uscore, int newscore);
Course mycourse;
Student tmp_student;
tmp_student.setMt1(60);
mycourse.addStudent(tmp_student);
cout<<mycourse.getStudent(0).getMt1()<<"\t"<<*mycourse.getStudent(0).getMt1()<<endl;
updateStudentScore(mycourse.getStudent(0).getMt1(), 90);
cout<<mycourse.getStudent(0).getMt1()<<"\t"<<*mycourse.getStudent(0).getMt1()<<endl;
return 0;
}
void updateStudentScore(int *uscore, int newscore){
*uscore = newscore;
};
I am fairly certain that my understanding of pointers and passing-by-whatevers is lacking and the way I defined functions here is creating the bug. I am sorry to inconvenience you guys. I would appreciate it if you could take a look.
Looking at your student/course code, i notice that Course::getStudent returns a Student rather than a Student &. Basically, that means each time you call getStudent(x), you get a temporary copy of student x, whose getMt1 function will give you a pointer to a temporary field, and any changes you make won't even survive past that statement.
If you have getStudent return a reference or pointer instead, your changes should persist to the Student contained in the array. (They still won't affect tmp_student, though, because addStudent copied it to add it to the array. If you want that reliably, then you need to redo quite a bit of stuff.)
I have a class that contains an array of object pointers as its member variable. I'm currently having an issue in getting the compiler to copy an object to the end of the array as when I step through the program the array of objects reads that its memory cannot be read. Anyone know what the issue might be?
void Notifications::operator+=(const iMessage& src) {
iMessage** temp2 = nullptr;
temp2 = new iMessage*[size+1];
if (size != 0){
for (int i = 0; i < size; i++) {
*temp2[i] = *messages[i];
}
}
*temp2[size] = src; //compiler states that it cannot read the data from temp2 after this point
delete[]messages;
for (int i = 0; i < size + 1; i++) {
*messages[i] = *temp2[i]; //Unhandled exception at 0x00C58F99 in w5.exe: 0xC0000005: Access violation reading location 0x00000000.
}
size++;
}
Notifications.h
#include "iMessage.h"
#include <vector>
namespace w5 {
class Notifications {
int size;
iMessage **messages;
public:
Notifications();
Notifications(const Notifications&);
Notifications& operator=(const Notifications&);
Notifications(Notifications&&);
Notifications&& operator=(Notifications&&);
~Notifications();
void operator+=(const iMessage&);
void display(std::ostream&) const;
};
}
IMessage.h
#ifndef _I_MESSAGE_H_
#define _I_MESSAGE_H_
// Workshop 5 - Containers
// iMessage.h
#include <iostream>
#include <fstream>
namespace w5 {
class iMessage {
public:
virtual void display(std::ostream&) const = 0;
virtual iMessage* clone() const = 0;
virtual bool empty() const = 0;
};
iMessage* getMessage(std::ifstream&, char);
}
#endif
Message.h
#include "iMessage.h"
namespace w5{
class Twitter : public iMessage {
std::string msg;
public:
Twitter(char, std::ifstream&);
virtual void display(std::ostream&) const;
virtual iMessage* clone() const;
virtual bool empty() const;
};
class Email : public iMessage {
std::string msg;
public:
Email(char, std::ifstream&);
virtual void display(std::ostream&) const;
virtual iMessage* clone() const;
virtual bool empty() const;
};
}
1) Just use vector.
2) You should always post exact compiler messages. "compiler states that it cannot read the data from temp2 after this point" is not good enough.
3) You allocate an array of pointers, and then dereference those pointers, but you never let the pointers point anywhere.
4) You delete the messages array and then proceed to copy back into it as if it was still there. (What you actually want to do is just assign messages = temp2.)
5) You're slicing objects all over the place, by using assignment to attempt to copy iMessage objects. There's a reason iMessage has a clone() function.
First you do
delete[]messages;
then you do
*messages[i] = *temp2[i];
attempting to access the array you've just deleted. I think you just want to take the pointer to the array you've just created:
messages = temp2;
You also do
*temp2[size] = src;
when temp2[size] doesn't point to anything. That should probably be
temp2[size] = src.clone();
to make a persistent copy of the argument and store it in the array.
It's rather tricky to follow this weird pointer-juggling; I think you also want to delete each element of messages before messages itself to avoid leaks. Why not just use std::vector to take care of memory allocation for you? That will reduce the whole insane dance to
std::vector<std::unique_ptr<iMessage>> messages;
void operator+=(const iMessage & src) {
messages.emplace_back(src.clone());
}
Also, _I_MESSAGE_H_ is a reserved name. You should remove the leading underscore.
You want to convert a const reference into a non-const pointer.
I wonder that the compiler doesn't throw errors. Which compiler you use?
Is something like this not possible?
void Notifications::operator+=(iMessage* src) {
I was not testing but this should also work:
void Notifications::operator+=(iMessage& src) {
*bar[foo] = &src;