C++ Implementing a copy constructor - c++

I am writing some code to implement a deep copy of an object.
Here is my code:
//---------------------------------------------------------------------------
#pragma hdrstop
#include <tchar.h>
#include <string>
#include <iostream>
#include <sstream>
#include <conio.h>
using namespace std;
//---------------------------------------------------------------------------
class Wheel
{
public:
Wheel() : pressure(32)
{
ptrSize = new int(30);
}
Wheel(int s, int p) : pressure(p)
{
ptrSize = new int(s);
}
~Wheel()
{
delete ptrSize;
}
void pump(int amount)
{
pressure += amount;
}
int getSize()
{
return *ptrSize;
}
int getPressure()
{
return pressure;
}
private:
int *ptrSize;
int pressure;
};
class RacingCar
{
public:
RacingCar()
{
speed = 0;
*carWheels = new Wheel[4];
}
RacingCar(int s)
{
speed = s;
}
RacingCar(RacingCar &oldObject)
{
for ( int i = 0; i < sizeof(carWheels)/sizeof(carWheels[0]); ++i)
{
Wheel oldObjectWheel = oldObject.getWheel(i);
carWheels[i]=new Wheel(oldObjectWheel.getSize(),oldObjectWheel.getPressure());
}
}
void Accelerate()
{
speed = speed + 10;
}
Wheel getWheel(int id)
{
return *carWheels[id];
}
void printDetails()
{
cout << carWheels[0];
cout << carWheels[1];
cout << carWheels[2];
cout << carWheels[3];
}
private:
int speed;
Wheel *carWheels[4];
};
#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
RacingCar testCar;
testCar.printDetails();
RacingCar newCar = testCar;
newCar.printDetails();
getch();
return 0;
}
//---------------------------------------------------------------------------
For some reason, my C++ builder crashes after compiling this code. Is there anything above that is not correct that would cause this to crash. There is no compile error, the program just crashes.

The problem is:
Wheel *carWheels[4];
and
*carWheels = new Wheel[4];
this only allocates 4 Wheels for carWheels[0]. Along with
return *carWheels[id];
If id is not 0, this will lead to undefined behavior because, as previously stated, only the first element is a valid pointer.
Besides this, the code is horrible. Avoid raw pointers. There are much better alternatives in C++. Use std::vector or std::array where you'd use a C-array, and smart pointers where you'd use raw ones.

Generally in my experience, if my compiler/tool crashes, I'm probably doing something so wrong that it never even occurred to the compiler writers to check for it.
The best way to track down such things is to comment out code until it works again, then slowly bring stuff back in until you find the offending part.
As a design note, I'd say that if it were me, I'd implement a copy constructor for Wheel as well, rather than having to write a complex deep copy constructor for classes like RacingCar that use it.

Related

How to model a book-library system in C using structs?

I am trying to learn C and C++ and I am struggling a bit with pointers. Concretely, I want to model a book-library system using some structs. A library could have more or less books, but we do not exactly the number. Below, I will post some snippet code:
This works but the number of books is known, not desired.
// library.h
#ifndef _LIBRARY_
#define _LIBRARY_
#include "book.h"
typedef struct {
int noBooks;
book books[10];
}library;
void addBook(book*, library*);
#endif
// library.c
#include "library.h"
void addBook(book* b, library* l) {
l->books[l->noBooks] = *b;
l->noBooks++;
}
// book.h
#ifndef _BOOK_
#define _BOOK_
#include <string.h>
#include <stdio.h>.
#include <stdlib.h>
typedef struct book_ {
int id;
char author[15];
char title[15];
}book;
void displayInfo(const book*);
#endif
//book.c
#include "book.h"
void displayInfo(const book* b) {
printf("Id: %d \n Author: %s \n Title: %s\n", b->id, b->author, b->title);
}
//main.cpp
#include<iostream>
extern "C" {
#include "book.h"
#include "library.h"
}
int main() {
std::cout << "Start" << std::endl;
book b1;
strcpy_s(b1.author, "Ab");
b1.id = 1;
strcpy_s(b1.title, "Ab");
book b2;
strcpy_s(b2.author, "Df");
b1.id = 2;
strcpy_s(b2.title, "Df");
library l1;
l1.noBooks = 0;
addBook(&b1, &l1);
addBook(&b2, &l1);
std::cout << l1.books[0].author << "\n";
std::cout << l1.books[1].author;
}
How should I modify it in order to add books without to know exactly the number (10 in this case)?
I tried more cases, for example:
// library.h
#ifndef _LIBRARY_
#define _LIBRARY_
#include "book.h"
typedef struct {
int noBooks;
book* books;
}library;
void addBook(book*, library*);
#endif
// library.c
#include "library.h"
void addBook(book* b, library* l) {
l->books[l->noBooks] = *b;
l->noBooks++;
}
Still, it does not work. Could you give me guidance/advice?
Thank you for your time!
To directly address the concern mentioned in your question, pointers aren't necessary for this program at all. At least not pointers that you need to write.
Given the discussion in the comments about what your code is, I'll chip in an answer that leans more into C++.
#include <iostream>
#include <string>
#include <vector>
class Book {
public:
Book() = default;
Book(int id, std::string auth, std::string title)
: m_id(id), m_author(auth), m_title(title) {}
friend std::ostream& operator<<(std::ostream& sout, const Book& book) {
return sout << "ID: " << book.m_id << "\nAuthor: " << book.m_author
<< "\nTitle: " << book.m_title << '\n';
}
private:
int m_id = 0;
std::string m_author;
std::string m_title;
};
class Library {
public:
void add_book(Book book) { m_books.push_back(book); }
std::size_t size() const { return m_books.size(); }
// The better approach would be to provide iterators so that you can access
// individial books from the library, much like you can with the vector,
// but that's a whole other level of work.
void print() const {
for (auto book : m_books) {
std::cout << book << '\n';
}
}
private:
std::vector<Book> m_books;
};
int main() {
Book b1(1, "Frank Herbert", "Dune");
Book b2(2, "Frank Herbert", "Dune Messiah");
Library l1;
l1.add_book(b1);
l1.add_book(b2);
l1.print();
std::cout << "Number of books in library: " << l1.size() << '\n';
}
Output:
ID: 1
Author: Frank Herbert
Title: Dune
ID: 2
Author: Frank Herbert
Title: Dune Messiah
Number of books in library: 2
As you can see, even a basic C++ (not C with std::cout, but idiomatic C++) implementation requires essentially a full re-write. And I noted one area where I really skimped. Your Library is just wrapping a container, and containers are typically built to be iterated through. But the effort of writing an iterator (it would just be wrapping the vector iterator) just didn't make sense for this answer.
For a toy program like this, you might be better off skipping the Library class completely and just declaring something like std::vector<Book> library; in your main() function and taking direct advantage of all the capabilities that std::vector provides.
The big takeaways in this snippet that will make the code easier to manage are:
Classes. Bundles your relevant data and functions together.
std::vector. A heap-allocated array that grows when needed and knows its own size.
std::string. Handles all the messy parts and far less error-prone.
Also on display is operator overloading. This allows you use your custom types as if they were native types. Much nicer than something like a display() function.
While all that C syntax is technically valid C++, philosophically it's completely wrong. You either want to learn C, or you want to learn C++. Choose one and stick with it. Blending the two the way you did will just lead to a bad time.
If you want to do this in C:
You can try to implement your own resizable library.
Something like this :
typedef struct {
int length;
int capacity;
book *books;
} library;
int add_book(library *lib, book *b) {
// Add a book to the library
assert(lib != NULL); // Check if library is valid
assert(b != NULL); // Check if book is valid
if(lib->length + 1 > lib->capacity) { // We run out of space for new books
lib->capacity *= 2;
lib->books = realloc(lib->books, lib->capacity * sizeof(book)); // Check for errors
lib->books[lib->length] = *b;
lib->length++;
printf("Increased library capacity and added book to library\n");
return 0;
}
else {
lib->books[lib->length] = *b;
lib->length++;
printf("Book added to library\n");
return 0;
}
}
If you want to do this in C++ (much easier):
You can use vector and just append values.
Here is a minimal implementation demonstrating how to dynamically add a book to your library and clean up the resources allocated:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct book {
int id;
char author[15];
char title[15];
};
struct library {
unsigned noBooks;
struct book *books;
};
// check for duplicate id?
struct library *library_add(struct library *l, struct book *b) {
if(!l) return NULL;
struct book *books = realloc(l->books, sizeof(struct book) * (l->noBooks + 1));
if(!books) {
printf("realloc failed\n");
return NULL;
}
l->books = books;
l->books[l->noBooks].id = b->id;
strcpy(l->books[l->noBooks].author, b->author);
strcpy(l->books[l->noBooks].title, b->title);
l->noBooks++;
return l;
}
void library_print(struct library *l) {
if(!l) return;
for(unsigned i = 0; i < l->noBooks; i++) {
printf("id = %d, author = %s, title = %s\n",
l->books[i].id,
l->books[i].author,
l->books[i].title
);
}
}
void library_destroy(struct library *l) {
if(!l) return;
free(l->books);
}
int main() {
struct library l = { 0, NULL };
library_add(&l, &(struct book) { 1, "Ab", "Ab"});
library_add(&l, &(struct book) { 2, "Df", "Df"});
library_print(&l);
library_destroy(&l);
return 0;
}

Member function doesn't work when using pointer to class

Scenario: I have two classes, each contains a pointer to the other (when using them, being able to refer to the other is going to be important so I deemed this appropriate). When I try accessing a private variable from one class via using the pointer to the other and a getter function inside that, it works perfectly.
Problem: Using a setter (in this case, addPoints)/manipulating the variables however leads to no result.
I'm new so anything here might be "improper etiquette" and bad practice. Feel free to point them out! But please also try to provide a solution. This is also my first question on SO, so please be gentle!
Related code pieces:
Team.h
#include "Driver.h"
using namespace std;
class Team {
int Points = 0;
vector<Driver*> Drivers;
public:
void addPoints(int gained); //does not work
int getPoints(); //works perfectly
Driver getDriver(int nr);
void setInstance(vector<Driver*> drivers);
};
Team.cpp
#include "Team.h"
#include "Driver.h"
using namespace std;
void Team::addPoints(int gained) {
this->Points = this->Points + gained;
}
int Team::getPoints() {
return this->Points;
}
Driver Team::getDriver(int nr) {
return *Drivers[nr];
}
void Team::setInstance(vector<Driver*> drivers) {
this->Drivers = drivers;
}
Driver.h
using namespace std;
class Team;
class Driver {
int Points = 0;
Team* DriversTeam;
public:
void SetTeam(Team& team);
Team getTeam();
int getPoints(); //works
void addPoints(int gained); //doesn't work
};
Driver.cpp
#include "Driver.h"
#include "Team.h"
using namespace std;
void Driver::SetTeam(::Team& team) {
this->DriversTeam = &team;
}
Team Driver::getTeam() {
return *DriversTeam;
}
int Driver::getPoints() {
return this->Points;
}
void Driver::addPoints(int gained) {
this->Points = this->Points + gained;
}
Initializer.cpp (linking drivers to teams)
void InitializeData(vector<Team>& teams, vector<Driver> &drivers) {
//(...)
//reads each team in from data file to memory
//key part:
vector<Driver*> teamsDrivers;
for (auto& iter : drivers) { //this loop mainly determines which driver to link with which teams
if (iter.getName().compare(values[4]) == 0) { //values is csv line data in a string vector. I guess not the prettiest parsing method here but will be revised
teamsDrivers.push_back(&iter);
}else if(iter.getName().compare(values[5]) == 0) {
teamsDrivers.push_back(&iter);
}
}
tempTeam.setInstance(teamsDrivers);
teams.push_back(tempTeam);
}
(linking driver to team)
//drivers are linked to teams last, as they are declared first (so I cannot link them to the yet nonexisting teams)
void LinkTeam(vector<Driver>& drivers, vector<Team>& teams) {
for (auto& driverIter : drivers) { //iterate through drivers
for (auto& teamIter : teams) { // iterate through teams
bool found = 0;
for (size_t i = 0; i < teamIter.DriverAmount(); i++) {
if (driverIter.getName() == teamIter.getDriver(i).getName()) {
driverIter.SetTeam(teamIter);
found = 1;
break;
}
}
if (found) { //exit iterating if driver is found
break;
}
}
}
}
Example of use in main.cpp
teams[0].addPoints(10);
drivers[3].getTeam().addPoints(15); //driver 3 is linked to team 0
cout << teams[0].getPoints(); //15
cout << drivers[3].getTeam().getPoints(); //15
teams[0].getDriver(1).addPoints(20); //driver 1 of team 0=driver[3]
drivers[3].addPoints(25);
cout << drivers[3].getPoints(); //25
cout << teams[0].getDriver(1).getPoints(); //25
Thanks for the help in advance.
This is quite simple:
Your getTeam() and getDriver() functions are returning copies of the objects, not references, so the addPoints() are performed on temporary copies and not the real ones.
To fix it, simply change the return types to references (add &):
Team& getTeam();
and
Driver& getDriver();

Nothing prints; do I need a main or should it work without it, theoretically?

I'd hate to ask this but I've been trying this for HOURS and I can't figure it out. I'm brand new to C++ and can't figure out why the sprintf_s won't put anything out at the end (or both of them for that matter). Basically, nothing happens in Visual Studio 2019 except the window pops up. I know it's a simple solution but I am going crazy trying to figure it out. Also, do I HAVE to have a main or should it work without it? Ok, also, does my constructor look ok? I have the green squiggly under it and not sure how to fix it or if I can ignore that. I appreciate all the help I can get! Thank you!
//#include "stdafx.h" - commented out as I think this version of VS does
//this automatically (I looked under precompiled headers and it was listed as "Precompiled Header File"
//and it wouldn't work unless I commented it out
#include <iostream>
using namespace std;
// Base Entree class
class Entree
{
protected:
char _entree[10];
public:
const char* getEntree()
{
return _entree;
}
};
// Base Side class
class Side
{
protected:
char _side[10];
public:
char* getSide()
{
return _side;
}
};
class Drink
{
protected:
char _drink[10];
public:
Drink()
{
cout << "\n Fill cup with soda" << endl;
strcpy_s(_drink, "soda");
}
char* getDrink()
{
return _drink;
}
};
// ADDED CODE:
class ComboMeal
{
private:
Entree* entree;
Side* side;
Drink* drink;
char _bag[100];
public:
ComboMeal(const char* type)
{
sprintf_s(_bag, "/n %s meal combo: ", type);
}
void setEntree(Entree * e)
{
entree = e;
}
void setSide(Side * s)
{
side = s;
}
void setDrink(Drink * d)
{
drink = d;
}
const char* openMealBag()
{
sprintf_s(_bag, "%s, %s, %s, %s", _bag, entree->getEntree(), side->getSide(), drink->getDrink());
return _bag;
}
};
int main()
{
}
As it's been said in the comments, in C++ the code that's executed is the one in the main function. Constructors are called when objects of the correspondent class are created, so you should at least have something like this:
int main(){
ComboMeal combo("my type one");
return 0;
}
A more complete example would be:
int main(){
ComboMeal combo("my type one");
combo.setEntree(new Entree);
combo.setSide(new Side);
combo.setDrink(new Drink);
cout << combo.openMealBag() << endl;
return 0;
}
(Of course this will print garbage, because the values within the new objects are not set)

Segmentation Fault in memcpy operation of a struct

I am adding the header file and cpp file (it has main fucntion).
AuctionPrices.h
#ifndef AuctionPrices_h
#define AuctionPrices_h
/*
*
* class AuctionPrices - maintains Buy Order, Sell Order books
*/
#include <bits/stdc++.h>
#include <map>
//#pragma pack(1)
struct Order
{
char * itemId;
char * auctionId;
int Side;
};
class AuctionPrices
{
public:
virtual int AddNewOrder(char *itemId, char *auctionId, int Side, int Price) = 0;
virtual int DeleteOrder(char *itemId, char *auctionId) = 0;
virtual int Print() = 0;
};
class AuctionPrice_Imp : public AuctionPrices
{
public:
AuctionPrice_Imp();
~AuctionPrice_Imp();
std::map <int, Order, std::greater< int >> BuyMap;
std::map <int, Order, std::less< int >> SellMap;
int AddNewOrder(char *itemId, char *auctionId, int Side, int Price);
int DeleteOrder(char *itemId, char *auctionId);
int Print();
};
#endif
AuctionPrices_Imp.cpp
/**
* Auction Price Class implementation
* Constructor, AddNewOrder, DeleteOrder, Print
*
*/
#include <bits/stdc++.h>
#include <map>
#include "AuctionPrices.h"
using namespace std;
AuctionPrice_Imp::AuctionPrice_Imp()
{
}
AuctionPrice_Imp::~AuctionPrice_Imp()
{
}
int AuctionPrice_Imp::AddNewOrder(char *itemId, char *auctionId, int Side, int Price)
{
Order order;
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
order.Side = Side;
if (Side == 1)
{
BuyMap.insert (std::pair<int,Order>(Price,order));
//buyLevels_.insert( std::pair< OfPrice, Level< OrderEntry > >( price, buyLevel ) );
}
else if (Side == 2)
{
SellMap.insert (std::pair<int,Order>(Price,order));
}
else
{
return 0;
}
return 1;
}
int AuctionPrice_Imp::DeleteOrder(char *itemId, char *auctionId)
{
return 0;
}
int AuctionPrice_Imp::Print()
{
std::map <int,Order,std::greater< int >>::iterator buy_it;
std::map <int,Order,std::less< int >>::iterator sell_it;
// Print Sell Map
for ( sell_it = SellMap.begin();sell_it != SellMap.end(); sell_it++)
{
std::cout << sell_it->first << '\t' << std::endl;
}
// Print Buy Map
for ( buy_it = BuyMap.begin();buy_it != BuyMap.end(); buy_it++)
{
std::cout << buy_it->first << '\t' << std::endl;
}
return 1;
}
int main()
{
AuctionPrice_Imp * auctionPrice_Imp = new AuctionPrice_Imp();
/*
AddNewOrder(“item1”, “auction1”, 1, 100)
AddNewOrder(“item1”, “auction2”, 1, 101)
AddNewOrder(“item2”, “order3”, 1, 99)
AddNewOrder(“item2”, “order4”, 2, 100)
*/
auctionPrice_Imp->AddNewOrder("item1", "auction1", 1, 100);
auctionPrice_Imp->AddNewOrder("item1", "auction2", 1, 101);
auctionPrice_Imp->AddNewOrder("item2", "order3", 1, 99);
auctionPrice_Imp->AddNewOrder("item2", "order4", 2, 100);
auctionPrice_Imp->Print();
}
When I am running the code its giving segmentation fault at the line:
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Please anyone can help or correct the code.
The functions I am calling are supposed to add the orders to the Maps: BuyMap and SellMap. Once they have added to those map, I am using a print function to print the values.
Order order;
This creates a new Order object. Order does not have a constructor, so none of its class members, itemId, and auctionId, get initialized to point to anything. These pointers are uninitialized, random garbage. Immediately afterwards:
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Since neither itemId, nor auctionId, point to sufficient memory that are at least strlen(itemId)+1 or strlen(auctionId)+1 in size, respectively, this results in undefined behavior, and your crash.
In C++, before using a pointer, it is your responsibility to make sure that the pointer is valid, and points to the correct object, objects, or sufficiently-sized memory buffers. C++ will not do that for you, you have to do all that work yourself.
But if your intent is to write modern C++ code, it is much simpler just to use C++ classes, like std::strings instead of plain char * pointers. std::strings automatically handle all these low-level details, manage memory properly, without making it your responsibility to do so. You will find a complete description of std::string and many examples of using it in your C++ textbook.
You should use std::string to avoid having to deal with low level issues of pointers and memory allocation. These are the issues that you are getting wrong in your code. Here's your code rewritten to use std::string
struct Order
{
std::string itemId;
std::string auctionId;
int Side;
};
int AuctionPrice_Imp::AddNewOrder(std::string itemId, std::string auctionId, int Side, int Price)
{
Order order;
order.itemId = itemId;
order.auctionId = auctionId;
order.Side = Side;
See how easy that is? The code to use std::string is no different to the code that handles int.

C++, Weird behavior of cout when trying to print integers

Im trying to write a class that stores an id and a value in an container class.
Im using an nested class as my data structure.
When im compiling the code sometimes it prints perfectly, sometimes it prints nothing and sometimes it prints half of the data then stops.
When i debug the code the same weird behavior occours, when it fails during debug it throws an error "Map.exe has triggered a breakpoint.", the Error occours in the print method when im using cout.
cmap.h
#pragma once
class CMap
{
public:
CMap();
~CMap();
CMap& Add(int id, int value);
void print() const;
private:
class container
{
public:
~container();
int container_id = 0;
int container_value = 0;
};
container* p_komp_;
int dim_ = -1;
void resize();
};
cmap.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
CMap::CMap()
{
p_komp_ = new container[0];
}
CMap::~CMap()
{
p_komp_ = nullptr;
cout << "destroy cmap";
}
CMap& CMap::Add(int id, int value)
{
resize();
p_komp_[dim_].container_id = id;
p_komp_[dim_].container_value = value;
return *this;
}
void CMap::resize()
{
container* temp_array = new container[++dim_];
if (dim_ == 0)
{
temp_array[0].container_id = p_komp_[0].container_id;
temp_array[0].container_value = p_komp_[0].container_value;
}
for (unsigned i = 0; i < dim_; i++)
{
temp_array[i].container_id = p_komp_[i].container_id;
temp_array[i].container_value = p_komp_[i].container_value;
}
p_komp_ = temp_array;
}
void CMap::print() const
{
for (unsigned i = 0; i <= dim_; i++)
{
cout << p_komp_[i].container_id;
cout << p_komp_[i].container_value;
}
}
CMap::container::~container()
{
cout << "destruct container";
}
Map.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
void main(void)
{
CMap m2;
m2.Add(1, 7);
m2.Add(3, 5);
m2.print();
}
These two things are a possible reason for your problem:
int dim_ = -1;
and
container* temp_array = new container[++dim_];
When you allocate, you increase dim_ from -1 to 0. That is you create a zero-sized "array", where every indexing into it will be out of bounds and lead to undefined behavior.
You also have memory leaks since you never delete[] what you new[]. I didn't look for more problems, but there probably a more.
And an "array" (created at compile-time or through new[]) will have indexes from 0 to size - 1 (inclusive). You seem to think that the "size" you provide is the top index. It's not, it's the number of elements.
It seems to me that you might need to take a few steps back, get a couple of good books to read, and almost start over.