Copy constructors & Dynamic Memory C++ [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 23 days ago.
Improve this question
Recently I've started working on my first OOP project and after having written the program I am trying to optimize it for code efficiency. I want to place the parts of the program that are being copied a lot on the heap.
I can't understand why in certain places objects are copied.
An example:
In the main.cpp movies object, which stories movie objects, is created. Add_movie function is called that checks if the movie we are trying to add has already been added, if not, we create a temp object, initialize its private members to the argument values being passed, append it to the vector of the movies object. A copy constructor would be called when movie object is being appended to the vector. WHY? I can't understand the part WHY is it being copied? Is it because of the scope???
If there was an object initialized in the main like
Movie movie1{arguments};
and other movie is created based on movie1
Movie movie2{movie1}.
It makes sense to me, but in the example I gave, it doesn't make sense to me at all
The example of the function I am referring to
bool Movies::add_movie(std::string name, std::string rating, int watched)
{
for (const Movie& obj : movies_list)
{
if (obj.get_name() == name) // search for a match
{
return false; // if found stop executing
}
}
Movie temp{ name, rating, watched }; // creates a new object and initializes its private members to the passed arguments
# movies_list.push_back(temp); // appends the object to the vector
# *** return true;
}
I don't know if it will help, but there is the code of the program
**main.cpp **
#include "Movie.h"
#include "Movies.h"
#include <iostream>
#include <string>
void add_movie(Movies& obj, std::string name, std::string rating, int watched)
{
if (obj.add_movie(name, rating, watched))
{
std::cout << name << " succesfully added" << std::endl;
}
else
{
std::cout << name << " already has been added" << std::endl;
}
}
// if the parent increment_watched function returns true, inform the user about the result of the operation
void increment_watched(Movies &obj, std::string name)
{
if (obj.increment_watched(name)) // if Movies::increment_watched returns
{
std::cout << name << " watch count succesfully incremented by 1" << std::endl;
}
else {
std::cout << name << " movie not found" << std::endl;
}
}
int main()
{
Movies list;
add_movie(list, "Fight Club", "A", 1);
add_movie(list, "Fight Club", "A", 1);
add_movie(list, "Inception", "A", 1);
increment_watched(list, "Fight Club");
increment_watched(list, "Else Test");
list.display();
return 0;
}
movies.cpp
#include "Movie.h"
#include "Movies.h"
#include <iostream>
bool Movies::add_movie(std::string name, std::string rating, int watched)
{
for (const Movie& obj : movies_list)
{
if (obj.get_name() == name) // search for a match
{
return false; // if found stop executing
}
}
Movie temp{ name, rating, watched }; // creates a new object and initializes its private members to the passed arguments
movies_list.push_back(temp); // appends the object to the vector
return true;
}
void Movies::display() const
{
if (movies_list.size() == 0) // checks the vector size
{
std::cout << "The list is empty" << std::endl;
}
else
{
std::cout << "\nThe list of the movies: " << std::endl;
std::cout << "----------------------------" << std::endl;
for (const Movie& obj : movies_list)
{
obj.display_members(); // accesses the private members of the object that are stored in the vector and outputs them to the user
}
}
}
bool Movies::increment_watched(std::string name)
{
for (Movie &obj : movies_list) // iterates through the movie objects until finds the match in name
{
if (obj.get_name() == name)
{
obj.increment_watched(); // increments watched by 1
return true;
}
}
return false;
}
movie.cpp
#include <string>
#include <iostream>
#include "Movie.h"
// constructor for initializing private members of the object
Movie::Movie(std::string name, std::string rating, int watched)
{
this->name = name;
this->rating = rating;
this->watched = watched;
}
// get methods
std::string Movie::get_name() const { return name; }
std::string Movie::get_rating() const { return rating; }
int Movie::get_watched() const { return watched; }
// display private members
void Movie::display_members() const
{
std::cout << "Name: " << get_name() << std::endl;
std::cout << "Rating: " << get_rating() << std::endl;
std::cout << "Times watched: " << get_watched() << std::endl;
std::cout << "\n" << std::endl;
}
// setter function
void Movie::increment_watched() {watched++;}
// DEBUGGING
Movie::Movie(const Movie &obj):name{obj.name}, rating{obj.rating}, watched{obj.watched} {std::cout << "copy constructor called for " << name << std::endl;}
Movie::~Movie() {std::cout << "destructor called for movie " << name << std::endl;}
Debugging the program for hours to see which parts are being copied, when copied, when destructed to get a better grasp.
Watching countless videos that explain the lifetime of the objects, copy constructors, destructors, but it still doesn't make sense for me!

push_back() takes an object and appends it at the end of the vector. It has to make a copy because it must keep the original object intact because you might need it later. If you want to avoid the copy, you’d have you use std::move to trigger the move constructor.
movies_list.push_back(std::move(temp));
However, in your example you basically want to construct an object at the end of the vector. emplace_back is just what you need; no copying or moving, just pass the constructor arguments.
movies_list.emplace_back(name, rating,watched);

Related

How to pass const pointer values in classes in C++

I'm new to the world of C++ (and OOP).
I'm learning about classes and pointers at this moment, but I'm stuck and hope someone can explain to me what I'm missing or should dig deeper into to broaden my understanding.
Example 1 works:
#include <iostream>
#include <string.h>
using namespace std;
class MyClass
{
private:
char* age;
public:
MyClass(const char* initData)
{
age = NULL;
cout << "In default constructor working on pointers" << endl;
age = new char [strlen(initData)+1];
strcpy(age,initData);
//age = initData;
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete [] age;
}
const char* GetAge()
{
return age;
}
};
int main()
{
//MyClass firstClass(10);
//cout << "First attempt: " ;
//cout << firstClass.GetAge() << endl;
MyClass secondClass("A test from B");
cout << "Second attempt: ";
cout << secondClass.GetAge() << endl;
return 0;
}
However This does not work:
#include <iostream>
#include <string.h>
using namespace std;
class MyClass
{
private:
int* age;
public:
MyClass(const int* initData)
{
cout << "In default constructor working on pointers" << endl;
age = new int;
//strcpy(age,initData);
age = initData;
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete age;
}
const int* GetAge()
{
return age;
}
};
int main()
{
MyClass firstClass(10);
cout << "First attempt: " ;
cout << firstClass.GetAge() << endl;
//MyClass secondClass("B");
//cout << "Second attempt: ";
//cout << secondClass.GetAge() << endl;
return 0;
}
I feel that it has to do with the fact that I pass an int to a constant pointer.
And then try to assign a constant from r-value to l-value with the = operator.
Although it think this is permitted, since I say 'const int* initData' and this tells the compiler to keep the data from changing but memory address can change?
So in my understanding, I pass value 10 to the class that makes a pointer in the default constructor, this makes a memory address and stores it in initData.
I then pass the r-value InitData (mem address) to the l-value age pointer, that accepts memory addresses.
If I try with the exact same code, but use char and copy data over in my first example it works...
Can anyone explain to me what I'm missing, Thanks in advance!
Edit:
I Think I found my solution and understand it better.
Could anyone verify that this is correct, or which is the (more) correct form:
Scenario 1:
#include <iostream>
using namespace std;
class MyClass
{
private:
int* age;
public:
MyClass(const int *initData)
{
cout << "In default constructor working on pointers" << endl;
age = new int;
(*age) = (*initData);
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete age;
}
const int* GetAge()
{
return age;
}
};
int main()
{
int aNum = 10;
MyClass firstClass(&aNum);
cout << "First attempt: " ;
cout << *firstClass.GetAge() << endl;
return 0;
}
Or Scenario 2:
#include <iostream>
using namespace std;
class MyClass
{
private:
int* age;
public:
MyClass(const int &initData)
{
cout << "In default constructor working on pointers" << endl;
age = new int;
(*age) = (initData);
}
~MyClass()
{
cout << "In destructor working on pointers" << endl;
delete age;
}
const int* GetAge()
{
return age;
}
};
int main()
{
MyClass firstClass(10);
cout << "First attempt: " ;
cout << *firstClass.GetAge() << endl;
return 0;
}
I Would think solution 2, as that uses reference to memory and thus speeds up the execution?
Thanks for the assistance already, and sorry for the long post...
First: you can not set a const pointer to a non-const pointer, you can circumvent this using a const_cast<int*>(initData) which gets rid of the const-ness of initData when assigning to age.
But i do not think this is what you want to achieve.
So first of all a pointer is just pointing to memory - that memory must therefore be managed by someone else than the pointer. Usually you only need a pointer if you want to reference something or iterate - if you intend to be the owner of that memory you might not want to use a pointer.
Secondly: if you start learning C++ now, try to learnt 'modern' C++ and utilize smart_pointers (see smart pointers form cppreference).
A rule of thumb: if you do not necessarily need a pointer (no need for iteration, direct memory access) use by reference instead.
But bottom line: your example looks like it is not meant to be used with pointers at all. Just store the int value.
class MyClass
{
private:
int age;
public:
// pass by const reference, this is cheap and good practice
MyClass(const int& initData)
{
cout << "In default constructor working on pointers" << endl;
// here the value of initData is actually copied into age
age = initData;
}
And if you really want to try pointers: start with the std::shared_ptr which is a ref-counting pointer easy to use.
Example:
#include <memory>
#include <iostream>
class test
{
private:
std::shared_ptr<int> age;
public:
// cheap and quick const ref
test(const std::shared_ptr<int>& data)
{
age = data;
}
void print()
{
std::cout << *age << std::endl;
std::cout << "Use count: " << age.use_count() << std::endl;
}
};
int main()
{
// here we store the data
int i = 17;
// here we have the shared_ptr
std::shared_ptr<int> p = std::make_shared<int>(i);
// here we pass it to the object
test t(p);
t.print();
return 0;
}

C++ - Updating value in pointer gets overridden

I've recently begun learning C++ and I'm having some trouble updating a pointer in my Movie class. I've got a feeling I have an issue somewhere in my Move/Copy constructors but have been trying to solve this issue for hours, swapping pointers to references to values and finally coming here for help.
I have a class Movie, which contains a string name, string rating and int watched member variables. Another class Movies, holds a vector of the movies. On movie, my method increment_watched is supposed to increment the int watched by one, the value does get incremented but it seems like the value is not saved. The display_all_movies method in Movies, which simply displays the movies that it stores holds the old value for watched. I know the issue is probably something really small but I haven't been able to work out why the value isn't being saved.
If someone could explain why the pointer value seems to be getting overridden I'd appreciate it greatly. Thanks in advance!
Code is below, there is some debug couts in there.
Movie.h
#ifndef _MOVIE_H_
#define _MOVIE_H_
#include <string>
#include <iostream>
class Movie {
private:
std::string *name;
std::string *rating;
int *watched;
public:
std::string get_name();
std::string get_rating();
int get_watched();
void increment_watched();
Movie(std::string name, std::string rating, int watched_val); // normal constructor
Movie(const Movie &source); // copy constructor
Movie(Movie &&source); // move constructor
~Movie();
};
#endif // _MOVIE_H_
Movie.cpp
#include "Movie.h"
std::string Movie::get_name() {
return *name;
}
std::string Movie::get_rating() {
return *rating;
}
int Movie::get_watched() {
return *watched;
}
void Movie::increment_watched() {
std::cout << *watched << std::endl;
(*watched)++; // TODO FIX!
std::cout << *watched << std::endl;
}
Movie::Movie(std::string name, std::string rating, int watched_val)
: name{nullptr}, rating{nullptr}, watched{nullptr}{
std::cout << "Creating movie " << watched_val << " with normal constructor" << std::endl;
this->name = new std::string{name};
this->rating = new std::string{rating};
this->watched = new int{watched_val};
}
Movie::Movie(const Movie &source)
: Movie(*source.name, *source.rating, *source.watched) {
std::cout << "Creating movie " << *source.watched << " with copy constructor" << std::endl;
}
Movie::Movie(Movie &&source)
: Movie(*source.name, *source.rating, *source.watched) {
std::cout << "Creating movie " << *source.watched << " with move constructor" << std::endl;
source.name = nullptr;
source.rating = nullptr;
source.watched = nullptr;
}
Movie::~Movie() {
delete name;
delete rating;
delete watched;
}
Movies.h
#ifndef _MOVIES_H_
#define _MOVIES_H_
#include <vector>
#include <string>
#include <iostream>
#include "Movie.h"
class Movies {
private:
static int count;
std::vector<Movie> *movies;
public:
void add_movie(std::string &&name, std::string &&rating, int &&watch);
void increment_movie_count(std::string &&name);
void display_all_movies();
void count_movies();
Movies();
Movies(const Movie &source); // copy constructor
Movies(Movie &&source); // move constructor
~Movies();
};
#endif // _MOVIES_H_
Movies.cpp
#include "Movies.h"
int Movies::count = 0;
void Movies::add_movie(std::string &&name, std::string &&rating, int &&watch) {
bool contains {false};
for(auto movie : *movies) {
if(movie.get_name() == name) {
contains = true;
}
}
if(!contains) {
movies->push_back(Movie{name, rating, watch});
count++;
}
}
void Movies::increment_movie_count(std::string &&name) {
for(auto movie : *movies) {
if(movie.get_name() == name) {
movie.increment_watched();
}
}
}
void Movies::display_all_movies() {
for(auto movie : *movies) {
std::cout << "Title " << movie.get_name() << " Rating " << movie.get_rating() << " Watched " << movie.get_watched() << std::endl;
}
}
void Movies::count_movies() {
std::cout << "There are " << count << " movies " << std::endl;
}
Movies::Movies() {
movies = new std::vector<Movie>{};
}
Movies::~Movies() {
delete movies;
}
And finally main.cpp
#include <iostream>
#include "Movies.h"
using std::cout;
using std::endl;
int main() {
Movies *my_movies;
my_movies = new Movies();
(*my_movies).count_movies();
my_movies->add_movie("Big", "PG-13", 2);
my_movies->increment_movie_count("Big");
my_movies->display_all_movies();
return 0;
}
Changefor(auto movie : *movies) to for(auto& movie : *movies) to update the original movie objects. Otherwise, you're only updating copies of the movie objects.

trying to get different outputs from polymorphic function

Hi StackOverflow community!
I'm expecting different outputs depending on the class of object to be printed but that's not the case.
Medium.h
#include "Datum.h"
#include "Person.h"
class Medium
{
public:
Medium(std::string initTitel);
virtual ~Medium(void);
void ausgabe() const;
bool ausleihen(Person person, Datum ausleihdatum);
void zurueckgeben();
unsigned int getID();
protected:
static unsigned int currentID;
unsigned int ID;
std::string titel;
bool status;
Datum datumAusgeliehen;
Person personAusgeliehen;
};
Medium.cpp
#include "Medium.h"
#include <string>
#include <iostream>
unsigned int Medium::currentID = 1;
Medium::Medium(std::string initTitel): titel(initTitel), status(false)
{
ID = currentID++;
}
Medium::~Medium(void) {}
void Medium::ausgabe() const
{
std::cout << "ID: " << ID << std::endl;
std::cout << "Titel: " << titel << std::endl;
switch (status)
{
case true:
std::cout << "Status : Das Medium ist seit dem "
<< datumAusgeliehen << " an "
<< personAusgeliehen.getName() << " ausgeliehen."
<< std::endl;
break;
case false:
std::cout << "Status: Medium ist zurzeit nicht verliehen." << std::endl;
break;
}
}
The function prints ID, title and status to console.
Now depending on the type of Medium, I would like to print extra information using the function void ausgabe() const.
Example: If the Medium is a book(in german buch = book), information about author should be printed, in addition to other information available in Medium class. i.e, I have got the subclass called Buch which also has an void ausgabe() const function, which should print this extra information in class Buch.
Buch.h
#include "Medium.h"
class Buch: public Medium
{
public:
Buch();
Buch(std::string initTitel, std::string initAutor);
virtual ~Buch();
void ausgabe() const;
private:
std::string autor;
};
Buch.cpp
#include "Buch.h"
Buch::Buch(std::string initTitel, std::string initAutor): Medium(initTitel), autor(initAutor)
{ // TODO Auto-generated constructor stub }
Buch::~Buch() { // TODO Auto-generated destructor stub }
void Buch::ausgabe() const
{
Medium::ausgabe();
std::cout << "Autor: " << autor << std::endl;
}
As far as I have: In the class Buch, while calling the output function ausgabe() the extra information autor will be printed automatically. But for the remaining informations from Medium class, could you help. Thanks for your help :)
Now depending on the type of Medium to be printed, I would like to add
extra information to be printed. E.g. if the Medium is a book,
information about author should be printed too.
So you are looking for dynamic-polymorphism. Then, you need to make void ausgabe()const function to virtual in your base class(Medium), in order to call it polymorphically. And you need to override it in other subclasses(for instance class Buch). In the given code anyways these are not there. In addition to that, you also need virtual destructor at your base class.
Then in your class Buch's ausgabe() should be:
void ausgabe()const override
{
Medium::ausgabe(); // call first base class's ausgabe()
std::cout << "autor :" << autor << std::endl;
}
Then in your main, you can do this: See an example code here
int main ()
{
std::unique_ptr<Medium> some_objects[2];
some_objects[0] = std::make_unique<Medium>("Some Title");
some_objects[1] = std::make_unique<Buch>("Title 2", "user9775960");
for(auto& obj_type: some_objects)
obj_type->ausgabe();
return 0;
}
PS: always try to post English written code in the community, so that everybody can follow.

C++ constructor variable values at runtime will not be overridden [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 years ago.
Improve this question
I am following a c++ course with Unity. I followed the instructor, but I halted at the part where he defines a constructor. For some reason the variables will not be overridden at runtime with the values I gave in the definition of my constructor.
Here is my code:
FBullCowGame.h
#pragma once
//#include <iostream>
#include <string>
class FBullCowGame {
public:
FBullCowGame();
void Reset() const; //TODO make a more rich return value
int GetMaxTries() const;
int GetCurrentTry() const;
bool CheckGuessValidity(std::string) const;
bool IsGameWon() const;
private:
int MyCurrentTry;
int MyMaxTries;
};
FBullCowGame.cpp
#include "FBullCowGame.h"
//#pragma region constructors
FBullCowGame::FBullCowGame() {
int MyCurrentTry = 666;
int MyMaxTries = 666;
}
//#pragma endregion
//#pragma region getters
void FBullCowGame::Reset() const { return; }
int FBullCowGame::GetMaxTries() const { return MyMaxTries; }
int FBullCowGame::GetCurrentTry() const { return MyCurrentTry; }
bool FBullCowGame::CheckGuessValidity(std::string) const { return false; }
bool FBullCowGame::IsGameWon() const { return false; }
//#pragma endregion
main.cpp
#include <iostream>
#include <string>
#include "FBullCowGame.h"
void PrintIntro();
void PlayGame();
std::string GetGuess();
bool AskToPlayAgain();
FBullCowGame BCGame;
int main() {
std::cout << BCGame.GetCurrentTry();
std::cout << BCGame.GetMaxTries();
bool bPlayAgain = false;
do {
PrintIntro();
PlayGame();
bPlayAgain = AskToPlayAgain();
} while (bPlayAgain);
return 0;
}
void PlayGame() {
int MaxTries = BCGame.GetMaxTries();
std::cout << MaxTries << "\n";
for (int i = 1; i <= MaxTries; i++) {
std::string Guess = GetGuess();
std::cout << "Your guess was: " << Guess << std::endl;
std::cout << std::endl;
}
}
void PrintIntro() {
constexpr int WORD_LENGTH = 9;
std::cout << "Welcome to Bulls and Cows, a fun word game.\n";
std::cout << "Can you guess the " << WORD_LENGTH;
std::cout << " letter isogram I'm thinking of?\n\n";
return;
}
//std::cout << "Your guess is: " << Guess << "\n\n";
std::string GetGuess() {
int CurrentTry = BCGame.GetCurrentTry();
std::string Guess = "";
std::cout << "Try " << CurrentTry << ". Enter your guess: ";
std::getline(std::cin, Guess);
return Guess;
}
bool AskToPlayAgain() {
std::cout << "Do you want to play again(y/n)? ";
std::string Response = "";
std::getline(std::cin, Response);
//std::cout << "First char is: " << ((Response[0] == 'y') || (Response[0] == 'Y')) << "\n";
return (Response[0] == 'y') || (Response[0] == 'Y');
}
I a outputting the values with these two lines inside main:
std::cout << BCGame.GetCurrentTry();
std::cout << BCGame.GetMaxTries();
I only get 0 for both values from the getter functions. I am a beginner in c++ and I need a bit of help. I was thinking it's an IDE problem, so I cleaned the solution, rebuilt, rerun, restarted the IDE and did that again. Any kind of help is appreciated. Thanks.
In your class declaration you have:
{
...
private:
int MyCurrentTry;
int MyMaxTries;
};
Then in your constructor you think you are initializing them with this:
FBullCowGame::FBullCowGame() {
int MyCurrentTry = 666;
int MyMaxTries = 666;
}
But what is actually happening here is that you are creating local stack variables with the same exact name as your class's members. Your class member variables can be seen by using the class's this pointer ->:
{
this->MyCurrentTry ...
this->MyMaxTries ...
}
as these two sets of variables are not the same. Your member variables are not even being initialized; the compiler might be smart enough to automatically initialize them with 0 but this isn't guaranteed as they can have any arbitrary value. You are only declaring and initializing stack variables that are local to the constructor only.
To fix this you have 3 options.
First it was already mentioned in the comments. Just remove the type int before the names in the constructor so that you are not declaring local variables but are actually using the members as such:
{
MyCurrentTry = 666;
MyMaxTries = 666;
}
The second option is to do the same but to use the class's this pointer ->
{
this->MyCurrentTry = 666;
this->MyMaxTries = 666;
}
The third and more preferred method is to use the class constructor's member initializer list.
FBullCowGame::FBullCowGame() :
MyCurrentTry( 666 ),
MyMaxTries( 666 ) {
}
This should explain what you was doing wrong within your class's constructor and why the variables were not being initialized to what you thought they should of been, and why you was getting the output you was seeing.
A side note; your class's Reset() function does absolutely nothing.
If you want to use it as you are thinking then you would want it to look like this:
// Remove the const qualifier; otherwise you will not able to modify
// the class's members with this function. "const" is usually good for
// methods that return a member that does not make any internal changes
// to the member or the class.
{
public:
void Reset();
};
FBullCowGame::Reset() {
MyCurrentTry = "whatever value to reset it to."
MyMaxTries = "whatever value to reset it to."
}

Optimizing sorting container of objects with heap-allocated buffers - how to avoid hard-copying buffers?

I was making sure I knew how to do the op= and copy constructor correctly in order to sort() properly, so I wrote up a test case. After getting it to work, I realized that the op= was hard-copying all the data_.
I figure if I wanted to sort a container with this structure (its elements have heap allocated char buffer arrays), it'd be faster to just swap the pointers around. Is there a way to do that? Would I have to write my own sort/swap function?
#include <deque>
//#include <string>
//#include <utility>
//#include <cstdlib>
#include <cstring>
#include <iostream>
#include <fstream>
#include <algorithm> // I use sort(), so why does this still compile when commented out?
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
using namespace std;
namespace fs = boost::filesystem;
class Page
{
public:
// constructor
Page(const char* path, const char* data, int size) :
path_(fs::path(path)),
size_(size),
rawdata_(new char[size])
{
// cout << "Creating Page..." << endl;
strncpy(rawdata_, data, size);
// cout << "done creating Page..." << endl;
}
// copy constructor
Page(const Page& other) :
path_(fs::path(other.path())),
size_(other.size()),
rawdata_(new char[other.size()])
{
// cout << "Copying Page..." << endl;
strncpy(data_, other.data(), size_);
// cout << "done copying Page..." << endl;
}
// destructor
~Page() { delete[] data_; }
// accessors
const fs::path& path() const { return path_; }
const char* data() const { return rawdata_; }
int size() const { return size_; }
// operators
Page& operator = (const Page& other) {
if (this == &other)
return *this;
char* newImage = new char[other.size()];
strncpy(newImage, other.data(), other.size());
delete[] data_;
rawdata_ = newImage;
path_ = fs::path(other.path());
size_ = other.size();
return *this;
}
bool operator < (const Page& other) const { return path_ < other.path(); }
private:
fs::path path_;
int size_;
char* rawdata_;
};
class Book
{
public:
Book(const char* path) :
path_(fs::path(path))
{
cout << "Creating Book..." << endl;
cout << "pushing back #1" << endl;
// below, the RawData will be coming from methods like
// fstream.read(char* buffer, int filesize); or
// unzReadCurrentFile(unzFile zipFile, char* buffer, int size);
pages_.push_back(Page("image1.jpg", "firstImageRawData", 17));
cout << "pushing back #3" << endl;
pages_.push_back(Page("image3.jpg", "thirdImageRawData", 17));
cout << "pushing back #2" << endl;
pages_.push_back(Page("image2.jpg", "secondImageRawData", 18));
cout << "testing operator <" << endl;
cout << pages_[0].path().string() << (pages_[0] < pages_[1]? " < " : " > ") << pages_[1].path().string() << endl;
cout << pages_[1].path().string() << (pages_[1] < pages_[2]? " < " : " > ") << pages_[2].path().string() << endl;
cout << pages_[0].path().string() << (pages_[0] < pages_[2]? " < " : " > ") << pages_[2].path().string() << endl;
cout << "sorting" << endl;
BOOST_FOREACH (Page p, pages_)
cout << p.path().string() << endl;
sort(pages_.begin(), pages_.end());
cout << "done sorting\n";
BOOST_FOREACH (Page p, pages_)
cout << p.path().string() << endl;
cout << "checking datas" << endl;
BOOST_FOREACH (Page p, pages_) {
char data[p.size() + 1];
strncpy((char*)&data, p.data(), p.size());
data[p.size()] = '\0';
cout << p.path().string() << " " << data << endl;
}
cout << "done Creating Book" << endl;
}
const Page& getFirstPage() { return pages_[0]; }
private:
deque<Page> pages_;
fs::path path_;
};
int main() {
Book* book = new Book("/some/path/");
// below is an example of where the rawdata is used
// by a method that has a char* parameter
ofstream outFile("outimage.jpg");
outFile.write(book->getFirstPage().data(), book->getFirstPage().size());
}
I wouldn't use raw char * in this scenario as it's going to be an unnecessary headache. Use std::string instead, which will remove the need for the copy constructor, assignment operator and destructor as the compiler-generated ones will be sufficient.
If you then find that copying the data is still a major bottleneck, you could use a boost::shared_ptr to hold the string if you can live with the additional level of indirection in normal use. That way, the string will not be copied if the containing object is copied and you still get the safety of RAII.
If using manual char* manipulation isn't part of your criteria for the exercise, you could use std::string and let it handle all the allocation issues for you. The std::swap function used by std::sort is even specialized to call std::string::swap for you, which means that it automatically only swaps the pointers to your string data rather than deep-copying.
If you want to use char* for exercise purposes, probably the easiest way to create a free-standing swap function that takes two Page references and just swaps the internal data pointers around. I believe that as long as sort can see a better match than the standard template, it will call your function instead getting the increased performance.
Finally, to answer your question about the header : Compilers are free to implement headers as actual files that include other headers (even ones that might not normally be expected). Almost certainly your iostream header is including algorithm directly or indirectly. On another compiler your code might fail to compile.