Here are the inserts of my code...
main.cpp
void addStuff(Journey& journey)
{
journey.addPerson("John Doe", "USA");
}
void demo()
{
Journey journey("Sweden");
addStuff(journey);
std::cout << journey;
}
int main(int argc, char* argv[])
{
demo();
return 0;
}
Journy.cpp
void Journey::addPerson(const char* name, const char* nationality)
{
add(Person(name, nationality));
}
void Journey::add(Person person)
{
persons_.push_back(person);
}
std::ostream& operator<<(std::ostream& out, const Journey& journey)
{
out << "Journey: " << journey.name_ << std::endl;
out << " Persons attending:" << std::endl;
for(Journey::PersonList::const_iterator person_it = journey.persons_.begin();
person_it != journey.persons_.end();
person_it++)
{
out << " " << *person_it;
}
return out;
}
Person.cpp
Person::Person(){}
Person::Person(const char* name, const char* nationality) : name_(0),
nationality_(0)
{
copyString(&name_, name);
copyString(&nationality_, nationality);
}
Person::Person(const Person& other): name_( other.name_),
nationality_( other.nationality_) {}
void Person::copyString(char** dest, const char* source)
{
unsigned int str_len = strlen(source);
char* str = new char[str_len+1];
strncpy(str, source, str_len);
str[str_len] = '\0';
*dest = str;
}
std::ostream& operator<<(std::ostream& out, const Person& person)
{
out << person.name_ << " (" << person.nationality_ << ")" << std::endl;
return out;
}
However, when I try to execute the code, as a result I get:
Persons attending:
P�� ()
I am not really sure what I am doing wrong. Could the problem be the scope and lifetime of variables? As I understood, a list container makes a copy of each entry, so the scope and lifetime shouldn't be the issue. I have also seen somewhere that in order for a class instance to be stored in the list, the class must have default constructor, copy constructor and an = operator overloaded. My class Person has all these characteristics.
The code I posted are just inserts that I found relevant for this issue.
If anyone could give me the slightest hint what the problem could be, it would be really appreciated.
With regards
You do have a copy-constructor, which is good since you do a lot of copying. However, you only do shallow copying, i.e. copy only the pointers and not the actual contents.
This means that if you make a copy of a Person object (like you do when calling Journey::add(Person person)) then you will have two objects both using the same pointers to the same memory. If your destructor (if you have any) free the memory, then the memory is free'd for both objects, but one of the object will still have the pointers to the now free memory, leading to undefined behavior when you try to dereference those pointers.
You need to do deep copying, in other words allocate new memory and copy the contents. Or do the sensible thing and use std::string.
Related
I have written this piece of code for better understanding the move semantic:
Main:
#include <iostream>
#include "Var.h"
struct AllocationMetrics {
uint32_t totalAllocated = 0;
uint32_t totalFreed = 0;
uint32_t CurrentUsage() {
return totalAllocated - totalFreed;
}
};
static AllocationMetrics allocationMetrics;
void *operator new(size_t size) {
allocationMetrics.totalAllocated += size;
return malloc(size);
}
void operator delete(void *memory, size_t size) {
allocationMetrics.totalFreed += size;
return free(memory);
}
static void printMemoryUsage () {
std::cout << "Current memory usage (bytes): " << allocationMetrics.CurrentUsage() << std::endl;
}
int main() {
printMemoryUsage();
Var v1{"0011223344556677889"};
printMemoryUsage();
Var v2 = std::move(v1);
printMemoryUsage();
v2 = "yyyyyyyyyyyyyyyyyyy";
printMemoryUsage();
}
Class Var:
class Var {
private:
std::string varName;
public:
explicit Var(std::string _varName) : varName(std::move(_varName)) {
std::cout << "ctor\n" << &varName << std::endl;
} //ctor
Var(const Var &otherVar) = delete;
Var(Var &&otherVar) noexcept : varName{std::move(otherVar.varName)} {
std::cout << "mtor" << std::endl;
}
Var& operator=(const std::string& var) {
std::cout << "copy\n";
varName = var;
return *this;
}
Var& operator=(std::string&& var) {
std::cout << "move\n";
varName = std::move(var);
return *this;
}
virtual ~Var() { std::cout << "dtor" << std::endl; };
bool operator==(const Var &rhs) const {
return varName == rhs.varName;
}
bool operator!=(const Var &rhs) const {
return !(rhs == *this);
}
friend std::ostream &operator<<(std::ostream &os, const Var &var) {
os << "varName: " << var.varName;
return os;
}
};
I have a class "Var" with one field of std::string type.
I construct a Var v1 and then a Var v2 using the move constructor on v1, and that work great because the memory allocation remains the same.
Then I want to assign a new varName to v2 (v2 = "yyyyyyyyyyyyyyyyyyy"). Since I have allocated a new constant string, the total memory allocation increases. But then there is an assignment to the varName field (in method Var& operator=(std::string&& var)) so I would expect that the previously allocated memory that holds "0011223344556677889" in varName were freed, and then varName were assigned to the newly allocated memory block.
So in other word, how can I free the memory allocated for the varName field and allocate a new memory block to be pointed by varName? Am I using the move semantic correctly?
v2 = "yyyyyyyyyyyyyyyyyyy". I think this might be the first cause for your misunderstanding. A string literal has type const char[N], not std::string.
Anyway, there is no guarantee that std::string::operator= allocates a new memory block. When the existing allocation is large enough, it's simpler and faster to reuse that. So, your question : "how can I free the memory allocated for the varName field and allocate a new memory block to be pointed by varName?" has no simple answer.
In theory, you could call .clear() followed by .shrink_to-fit() but even that is non-binding. There's just no good reason in normal C++ programs to do what you want, so there is no method in std::string for that.
I've added debug output in the new and delete overloads: https://godbolt.org/z/Tn8EYfxPx
With that I get the following output:
Current memory usage (bytes): 0
allocate 20 <--- Var v1{"0011223344556677889"};
ctor
0x7fff040c9d88
Current memory usage (bytes): 20
mtor <--- Var v2 = std::move(v1);
Current memory usage (bytes): 20
allocate 20 <--- v2 = "yyyyyyyyyyyyyyyyyyy";
move
delete 20
Current memory usage (bytes): 20
dtor
delete 20
dtor
As you can see when you write v2 = "yyyyyyyyyyyyyyyyyyy"; the compiler invokes Var& operator=(std::string&& var) {. For this the C string is first converted to std::string causing the allocation. Then the move happens and swaps the 2 strings around. Last the temporary string is destructed causing the delete of the old contents of v2.
Note: the move could also delete the old contents directly but I think it swaps contents as that is faster in some cases.
PS: You could add a assignment operator using string_view that resizes the string and copies the contents. This would avoid the allocation and deallocation for the std::string temporary.
I am looking at this pool allocator implementation. I have actually modified it a bit and my full code is:
template <class T, size_t T_per_page = 200>
class PoolAllocator
{
private:
const size_t pool_size = T_per_page * sizeof(T);
std::vector<T *> pools;
size_t count;
size_t next_pos;
void alloc_pool() {
next_pos = 0;
void *temp = operator new(pool_size);
pools.push_back(static_cast<T *>(temp));
}
public:
PoolAllocator() {
count = 0;
alloc_pool();
}
void* allocate() {
if (next_pos == T_per_page)
alloc_pool();
void* ret = pools.back() + next_pos;
++next_pos;
++count;
return ret;
}
size_t getSize() const
{
return T_per_page * (pools.size() - 1) + next_pos;
}
size_t getCount() const
{
return count;
}
size_t getCapacity() const
{
return T_per_page * pools.size();
}
T* get(size_t index) const
{
if (index >= getCount()) { return NULL; }
size_t poolIndex = index / T_per_page;
return pools[poolIndex] + (index % T_per_page);
}
~PoolAllocator() {
std::cout << "POOL ALLOCATOR DESTRUCTOR CALLED" << std::endl;
while (!pools.empty()) {
T *p = pools.back();
size_t start = T_per_page;
if (pools.size() == 1){
start = next_pos;
}
std::cout << "start: " << start << std::endl;
for (size_t pos = start; pos > 0; --pos)
{
std::cout << "pos: " << pos << std::endl;
p[pos - 1].~T();
}
operator delete(static_cast<void *>(p));
pools.pop_back();
}
}
};
template<class T>
PoolAllocator<T>& getAllocator()
{
static PoolAllocator<T> allocator;
return allocator;
}
class Node
{
private:
int id;
std::vector<float> vertices;
public:
Node() : id(42)
{
std::cout << "Node constructor called" << std::endl;
}
~Node(){ std::cout << "Node destructor called" << std::endl; }
void* operator new(size_t size)
{
std::cout << "Node operator new called" << std::endl;
return getAllocator<Node>().allocate();
}
void operator delete(void*)
{
std::cout << "Node operator delete called" << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Node* n1 = new Node();
Node* n2 = new Node();
Node* n3 = new Node();
Node* n4 = new Node();
std::cout << "Count: " << getAllocator<Node>().getCount() << " size: " << getAllocator<Node>().getSize() << " capacity: " << getAllocator<Node>().getCapacity() << std::endl;
while (true){}
return 0;
}
When I run this code in visual studio it appears to work correctly up until I close the console at which point I get an access violation error. I have tried manually calling the destructor on the allocator and it appears to work properly but I must be making a mistake somewhere. The error I get is:
Can anyone spot where I am making my mistake?
Edit 1:
Upon further investigation it will still crash even without the new Node lines in main. Seems to be related to getAllocator() method and how the destructor is called maybe? Or the fact that the allocator is static??
Edit 2:
I actually don't think it has anything to do with my allocator at all! If I try the code:
class Node2
{
private:
int x;
public:
Node2():x(42){std::cout << "Node2 constructor called" << std::endl;};
Node2(const Node2& other){ std::cout << "Node2 copy constructor called" << std::endl; };
~Node2(){ std::cout << "Node2 destructor called" << std::endl; };
};
Node2& Test(){
static Node2 myIndex;
return myIndex;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test();
while (true){}
return 0;
}
It results in the same error! The plot thickens. I assumed being new to writing custom allocators that the allocator code was the issue. Still not sure why exactly this error is happening for my smaller code yet...
Writing an answer as I can't comment on the question.
I can't spot any obvious error in the last code. Are you sure you are compiling the right file and not an old unsaved version and such?
You can try to remove the line
while (true){}
And let the program just end normally.
Also, you can try to run your code in debug mode, single-stepping the instructions to find the one causing troubles.
I can spot some problems with that pool allocator.
PoolAllocator owns resources, but there's neither special copy constructor nor assignment. Most likely you should declare them deleted. And provide move-constructor and move-assignment. Though not a factor in this particular example, it may protect you from absendmindedly returning an allocator by value.
Function alloc_pool() resets next_pos before the new chunk is allocated. An exception, if ever thrown by operator new, would leave the pool in an inconsistent state.
Likewise, an exception in pools.push_back() would see the new chunk leaked. I believe std::vector<std::vector<std::byte>> would do just right, what with modern vectors being moveable. But if you absolutely want to use a vector of raw pointers, you should reserve extra space in pools, then allocate new chunk, and only then call push_back and modify the state.
Constructor of PoolAllocator may throw for no good reason.
Since allocate() method have to call alloc_pool() anyway, why calling it in the constructor? You could have a trivial noexcept constructor simply by leaving all allocation work to allocate().
PoolAllocator::allocate() and PoolAllocator::~PoolAllocator() are not symmetric. The former returns raw memory with no initialized object, while the latter assumes there's a properly constructed object in every allocated slot. That assumption is dangerous and very fragile. Imagine, for example, that T::T() throws.
It seems that getSize() and getCount() always return the same value. Is it intended?
Destructor will delete next_pos objects in the first pool, pools[0], and T_per_page objects in every other pool. But it should delete next_pos objects in the last pool.
You're in for wonderful bugs if T:~T() called from destructor of the pool ever tried to allocate another object from that very same pool. Such scenario may seem weird, but well, technically it can happen. Destructor'd better swap the current state of the pool to local variables and work on them. Repeating, if necessary.
That infinite loop in main() could spoil the destruction of global objects. Compiler could be smart enough to figure out that return is unreachable and skip the destruction part altogether.
pool_size could be a static member.
I have a snippet of code here and I have a vector of smart pointers objects that are filled, how would I be able to print all the values of all the objects using range based for loops? I do not want the addresses, but the value. Thank you in advance.
void printInfo(const std::vector< std::unique_ptr<Bird> >&fullData )
{
for(auto &info : fullData)
{
std::cout<< &info <<endl; //I want this to print getName() for each object, but how do I do that with range-based-for-loop? Something like this.. info->getName()
}
}
void fillFlock( std::vector< std::unique_ptr<Bird> > &cage)
{
size_t cageSize;
std::string name;
std::cout << "Bird cage size: " <<std::endl;
std::cin >> cageSize;
//set container size
cage.resize(cageSize);
for(auto &bird : cage)
{
std::cout<<"Bird Name " <<std::endl;
std::cin >> name;
bird.reset(new Bird(name));
}
}
int main()
{
std::vector< std::unique_ptr<Bird> > m_flock;
fillFlock(m_flock);
printInfo(m_flock);
}
You're actually making a new pointer to your unique pointers, and then printing the address of that. Use & to make a pointer and * to dereference (get the value). In other words,
std::cout << *info << std::endl;
EDIT: Question was changed and extra context added
If you want to call the function on info, then call the function,
std::cout << info->getName() << std::endl;
The type of info is just std::unique_ptr<Bird>& if that is what is throwing you.
Perhaps you want this to happen automatically with the streaming operator. A way of doing this is to define a operator<< that takes your Bird class. You can do this by adding the following declaration to your Bird class,
class Bird {
friend std::ostream& operator<<(std::ostream& out, const Bird& bird);
};
and then in your source file add the definition,
std::ostream& operator<<(std::ostream& out, const Bird& bird) {
return out << bird.getName();
}
This assumes that your getName function is const-qualified, which it really should be.
I am trying to write a copy constructor for the Shape class, so that it prints the address of the name of s2.
Here is my code:
class Shape {
private:
int x;
int y;
string * name;
public:
//constructor
Shape() {
cout << "Inside the constructor" << endl;
}
//Copy constructor
Shape(Shape& source) {
cout << "Copy constructor called" << endl;
name = new string[name];
copy(source.name, source.name, this->getName);
}
//Destructor
~Shape() {}
void setX(int px) {
x = px;
}
void setY(int py) {
y = py;
}
void setName(string * str) {
name = str;
}
string * getName() {
return name;
}
int main()
{
Shape s1;
s1.setName( new string("first shape") );
Shape s2(s1);
cout << s1.getName() << endl; //will display the address of name for s1
cout << s2.getName() << endl; //will display the address of name for s2
return 0;
}
As you created the string pointer member name for s1 and you're just copying it to s2 when invoking the copy constructor, it's just the expected behaviour that it displays the same address as for s1 - it simply copies the pointer.
If you want a unique name per shape, just create a static method / free function that creates a new name, and call that one in both, constructor and copy constructor, to give each new instance a unique name.
For what it's worth, using the new operator here is not really common (are you coming from a Java background?) - you may just want to use a regular std::string, in which case you don't have to do the memory management yourself (your code basically has a memory leak right now, because you don't call delete anywhere to free the memory allocated via new).
P.S.: Just saw you just edited and changed your code, while I was typing my answer... I won't keep track of the changes (please excuse that), but I leave my answer here for what it's worth.
Could you please try following code?
//Copy constructor
Shape(Shape& source) {
cout << "Copy constructor called" << endl;
name = new string[name];
*name = *source.name;
}
I'm currently writing a logging class (just for practice) and ran into an issue. I have two classes: The class Buffer acts as a temporary buffer and flushes itself in it's destructor. And the class Proxy that returns a Buffer instance, so I don't have to write Buffer() all the time.
Anyways, here is the code:
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
class Buffer
{
private:
std::stringstream buf;
public:
Buffer(){};
template <typename T>
Buffer(const T& v)
{
buf << v;
std::cout << "Constructor called\n";
};
~Buffer()
{
std::cout << "HEADER: " << buf.str() << "\n";
}
Buffer(const Buffer& b)
{
std::cout << "Copy-constructor called\n";
// How to get rid of this?
};
Buffer(Buffer&&) = default;
Buffer& operator=(const Buffer&) & = delete;
Buffer& operator=(Buffer&&) & = delete;
template <typename T>
Buffer& operator<<(const T& v)
{
buf << v;
return *this;
}
};
class Proxy
{
public:
Proxy(){};
~Proxy(){};
Proxy(const Proxy&) = delete;
Proxy(Proxy&&) = delete;
Proxy& operator=(const Proxy&) & = delete;
Proxy& operator=(Proxy&&) & = delete;
template <typename T>
Buffer operator<<(const T& v) const
{
if(v < 0)
return Buffer();
else
return Buffer(v);
}
};
int main () {
Buffer(Buffer() << "Test") << "what";
Buffer() << "This " << "works " << "fine";
const Proxy pr;
pr << "This " << "doesn't " << "use the copy-constructor";
pr << "This is a " << std::setw(10) << " test";
return 0;
}
Here is the output:
Copy-constructor called
HEADER: what
HEADER: Test
HEADER: This works fine
Constructor called
HEADER: This doesn't use the copy-constructor
Constructor called
HEADER: This is a test
The code does exactly what I want but it depends on RVO. I read multiple times that you should not rely on RVO so I wanted to ask how I can:
Avoid RVO completely so that the copy constructor is called every time
Avoid the copy constructor
I already tried to avoid the copy constructor by returning a reference or moving but that segfaults. I guess thats because the temporary in Proxy::operator<< is deleted during return.
I'd also be interested in completely different approaches that do roughly the same.
This seems like a contrived problem: Firstly, the code works whether RVO is enabled or disabled (you can test it by using G++ with the no-elide-constructors flag). Secondly, the way you are designing the return of a Buffer object for use with the << operator can only be done by copying†: The Proxy::operator<<(const T& v) function creates a new Buffer instance on the stack, which is then deleted when you leave the function call (i.e. between each concatenation in pr << "This " << "doesn't " << "use the copy-constructor";); This is why you get a segmentation fault when trying to reference this object from outside the function.
Alternatively, you could define a << operator to use dynamic memory by e.g. returning a unique_ptr<Buffer>:
#include <memory>
...
std::unique_ptr<Buffer> operator<<(const T& v) const
{
if(v < 0)
return std::unique_ptr<Buffer>(new Buffer());
else
return std::unique_ptr<Buffer>(new Buffer(v));
}
However, your original concatenation statements won't be compilable, then, because Proxy::operator<<(const T& v) now returns an object of type std::unique_ptr<Buffer> rather than Buffer, meaning that this returned object doesn't have its own Proxy::operator<<(const T& v) function defined and so multiple concatenations won't work without first explicitly de-referencing the returned pointer:
const Proxy pr;
std::unique_ptr<Buffer> pb = pr << "This ";
// pb << "doesn't " << "use the copy-constructor"; // This line doesn't work
*pb << "doesn't " << "use the copy-constructor";
In other words, your classes rely inherently on copying and so, if you really want to avoid copying, you should throw them away and completely re-design your logging functionalities.
† I'm sure there's some black-magic voodoo which can be invoked to make this possible --- albeit at the cost of one's sanity.