vector element, accessed through raw pointer, unexpectedly changes value - c++

Unexpected behavior of the following program (as short as I could make it):
#include <vector>
#include <iostream>
class Entry;
class CachedPayload {
public:
CachedPayload(const Entry* const o) : owner_(o) {}
void info(const char* where);
private:
const Entry* const owner_;
// meaningful payload not shown in this minimal example
};
class Entry {
public:
Entry(int i) : cached(this), my_i(i) {}
void showEntry(const char* where) const {
std::cout << where << ": this=" << this << ", i=" << my_i << std::endl; }
CachedPayload cached;
private:
int my_i;
};
void CachedPayload::info(const char* where) { owner_->showEntry(where); }
class CachingVector {
public:
CachingVector() {
resize();
data_.at(0).cached.info("GET");
}
void resize() {
data_.push_back(Entry(97));
data_.at(0).cached.info("RSZ");
}
private:
std::vector<Entry> data_;
};
int main()
{
CachingVector vec;
}
Outcome:
$ clang++-6.0 h.cpp && a.out
RSZ: this=0x7ffe1dc52dc8, i=97
GET: this=0x7ffe1dc52dc8, i=4206609
$ g++ h.cpp && a.out
RSZ: this=0x7ffc5e977040, i=97
GET: this=0x7ffc5e977040, i=-578764228
Why is the value of vec.data_[0].my_i, when accessed through vec.data_[0].cached.owner_, overwritten in a nonsensical, compiler-dependent way?
When I merge the two-line implementation of CachingVector::resize() into the constructor CachingVector(), then i=97 stays uncorrupted.

You are storing a pointer to a temporary in your vector (specifically in CachedPayload::owner_). That's the cause of the problem. Once the temporary has been destroyed you have a dangling pointer.
I added this to your code
~Entry() { std::cout << "destroyed " << this << std::endl; }
and this
CachingVector() {
data_.reserve(1); // prevent reallocation
resize();
data_.at(0).cached.info("GET");
}
New output is
destroyed 00000000001AF588
RSZ: this=00000000001AF588, i=97
GET: this=00000000001AF588, i=-858993460
As you can see you are accessing an object which has been destroyed, which is undefined behaviour of course.
To fix this I think you just need to define a copy constructor and assignment operator for Entry that make sure cached.owner_ always has the correct value.
Entry(const Entry& rhs) : cached(this), my_i(rhs.my_i) {}
Entry& operator=(const Entry& rhs) { my_i = rhs.my_i; return *this; }

Related

Member variable seemingly gets initialized twice

I have the following classes:
Bar.hpp
#include <string>
class Bar
{
public:
Bar(const std::string& info);
std::string getInfo() { return info; }
protected:
private:
std::string info;
};
Bar.cpp:
#include <Bar.hpp>
Bar::Bar(const std::string& info)
: info(info) { }
Foo.hpp:
#include <string>
#include <vector>
#include <Bar.hpp>
class Foo
{
public:
static void printInfoStore();
static Foo* getFoo(const std::string& name);
Foo() {};
std::string getName() { return name; }
std::vector<Bar> getBars();
void addBar(const std::string& info);
protected:
private:
static std::vector<Foo> infoStore;
Foo(const std::string& name);
std::vector<Bar> bars{};
std::string name;
};
Foo.cpp
#include <iostream>
#include <Foo.hpp>
Foo::Foo(const std::string& name)
: name(name) { }
//static
std::vector<Foo> Foo::infoStore(0);
//static
void Foo::printInfoStore() {
std::cout << "InfoStore is { ";
for (Foo& foo : infoStore) {
std::cout << foo.getName() << "=[ ";
for (Bar& bar : foo.getBars()) {
std::cout << bar.getInfo() << " ";
}
std::cout << "] ";
}
std::cout << " }" << std::endl;
}
//static
Foo* Foo::getFoo(const std::string& name) {
for (Foo& foo : infoStore) {
if (foo.getName() == name) {
return &foo;
}
}
Foo* foo = new Foo(name);
infoStore.push_back(*foo);
return foo;
}
std::vector<Bar> Foo::getBars() {
return bars;
}
void Foo::addBar(const std::string& info) {
Bar* bar = new Bar(info);
bars.push_back(*bar);
}
Basically there is a static vector that holds multiple Foo objects each of which has a vector of Bar objects.
Then I have the following main.cpp:
#include <Foo.hpp>
#include <Bar.hpp>
int main(int argc, char *argv[])
{
Foo::printInfoStore();
Foo::getFoo("Foo1")->addBar("info11"); // info11 is not added to Foo1
Foo::printInfoStore();
Foo::getFoo("Foo1")->addBar("info12");
Foo::printInfoStore();
Foo::getFoo("Foo1")->addBar("info13");
Foo::printInfoStore();
Foo::getFoo("Foo2")->addBar("info21"); // info21 is not added to Foo2
Foo::printInfoStore();
Foo::getFoo("Foo2")->addBar("info22");
Foo::printInfoStore();
return 0;
}
The output is the following:
InfoStore is { }
InfoStore is { Foo1=[ ] }
InfoStore is { Foo1=[ info12 ] }
InfoStore is { Foo1=[ info12 info13 ] }
InfoStore is { Foo1=[ info12 info13 ] Foo2=[ ] }
InfoStore is { Foo1=[ info12 info13 ] Foo2=[ info22 ] }
The strange thing is that the first Bars added for each Foo object (info11 and info21) do not get added. My guess is that there might be a second initialization of the bars vector that happens after the parent Foo object but I don't know if this is the case, nor I can find a rationale behind it.
I tried to initialize the bars vector explicitly within the foo constructor but to no avail: the first Bar added is always discarded.
So why does it happen? What's wrong with my code? What can be done to avoid that behavior?
All of your news are causing memory leaks. None of this code should be using new at all, since none of the vectors are holding pointers.
For that matter, since getFoo() always returns a valid object, whether an existing object or newly-pushed object, it should return a Foo& reference to that object rather than a Foo* pointer (you can return a pointer if you really want to, but I would not advise it).
Either way, you would have to make sure that whatever you do return actually refers to an object that is inside of your vector. Your output is not what you expect because the code is NOT doing this correctly, which is the root of your problem.
When you call getFoo() for a non-existent object, you create a new object, then push a copy of that object into your vector, and then return a pointer to the new'ed object, not a pointer to the copied object. So, any values you subsequently store in the new'ed object appear to be discarded when you print the vector later, since the values don't exist in the copied object that is actually inside of the vector. When you call getFoo() again for an existing object, you return a pointer to the copied object that is inside the vector, and you do not create a new object.
On a similar note, getBars() should also return a reference to its vector, not return a copy of its vector by value.
With all of that said, try something more like this instead:
Bar.hpp
#include <string>
class Bar
{
public:
Bar(const std::string& info);
std::string getInfo() const;
private:
std::string info;
};
Bar.cpp:
#include <Bar.hpp>
Bar::Bar(const std::string& info)
: info(info) { }
std::string Bar::getInfo() const
{ return info; }
Foo.hpp:
#include <string>
#include <vector>
#include <Bar.hpp>
class Foo
{
public:
static void printInfoStore();
static Foo& getFoo(const std::string& name);
std::string getName() const;
std::vector<Bar>& getBars();
const std::vector<Bar>& getBars() const;
void addBar(const std::string& info);
private:
static std::vector<Foo> infoStore;
std::vector<Bar> bars;
std::string name;
Foo(const std::string& name);
};
Foo.cpp
#include <iostream>
#include <Foo.hpp>
Foo::Foo(const std::string& name)
: name(name) { }
//static
std::vector<Foo> Foo::infoStore;
//static
void Foo::printInfoStore() {
std::cout << "InfoStore is { ";
for (const Foo& foo : infoStore) {
std::cout << foo.getName() << "=[ ";
for (const Bar& bar : foo.getBars()) {
std::cout << bar.getInfo() << " ";
}
std::cout << "] ";
}
std::cout << " }" << std::endl;
}
//static
Foo& Foo::getFoo(const std::string& name) {
for (Foo& foo : infoStore) {
if (foo.getName() == name) {
return foo;
}
}
infoStore.push_back(Foo(name));
return infoStore.back();
// or, in C++11..14:
// infoStore.emplace_back(name);
// return infoStore.back();
// or, in C++17 onward:
// return infoStore.emplace_back(name);
}
std::string Foo::getName() const {
return name;
}
std::vector<Bar>& Foo::getBars() {
return bars;
}
const std::vector<Bar>& Foo::getBars() const {
return bars;
}
void Foo::addBar(const std::string& info) {
bars.push_back(Bar(info));
// or, in C++11 onward:
// bars.emplace_back(info);
}
main.cpp
#include <Foo.hpp>
#include <Bar.hpp>
int main(int argc, char *argv[])
{
Foo::printInfoStore();
Foo::getFoo("Foo1").addBar("info11");
Foo::printInfoStore();
Foo::getFoo("Foo1").addBar("info12");
Foo::printInfoStore();
Foo::getFoo("Foo1").addBar("info13");
Foo::printInfoStore();
Foo::getFoo("Foo2").addBar("info21");
Foo::printInfoStore();
Foo::getFoo("Foo2").addBar("info22");
Foo::printInfoStore();
return 0;
}
You store copy in your vector (with memory leaks).
Fixed version:
Foo* Foo::getFoo(const std::string& name) {
for (Foo& foo : infoStore) {
if (foo.getName() == name) {
return &foo;
}
}
return &infoStore.emplace_back(Foo{name});
}
void Foo::addBar(const std::string& info) {
bars.emplace_back(info);
}
Demo

How can I prevent Lua/Sol2 from deleting a user type when it was created outside of Lua?

I've run into an issue where a parameter (a user type) I pass into Lua function from C++ causes a crash when the Lua object is destroyed. Note I am using Sol2 in addition to Lua.
I discovered this is happening because Lua appears to be creating a copy of the parameter I passed in, and once the lua object is destroyed, it also destroys that copy. However, one of the member variables of that copy is a pointer to another object. Thus deleting it, deletes the pointer held by the original object, and when accessed causes the crash.
Is there anyway around this? Such as not copying the object but using a pointer to it, or not deleting objects not "owned" by lua/sol2.
I've created a sample project to demonstrate the issue.
LuaWrapper.h
#pragma once
#include <string>
#include <map>
#pragma warning(push, 0)
#define SOL_ALL_SAFETIES_ON 1
#include "sol.hpp"
#pragma warning(pop)
class SharedClass;
class LuaWrapper
{
public:
LuaWrapper();
~LuaWrapper();
public:
void RunFuncWithSharedClassParam(
const SharedClass& shared_class);
protected:
// Returns true if script loaded
bool LoadScriptIfNeeded(
const std::string& file_path);
virtual void RegisterUserTypes(
sol::state& lua_state);
private:
sol::function GetFunction(
const std::string& file_path,
const std::string& function_name);
protected:
typedef std::map<std::string, sol::state> LuaStates;
LuaStates m_lua_states;
private:
// No copies, do not implement
LuaWrapper(const LuaWrapper& rhs) = delete;
LuaWrapper& operator=(const LuaWrapper& rhs) = delete;
};
LuaWrapper.cpp
#include "LuaWrapper.h"
#include "SharedClass.h"
LuaWrapper::LuaWrapper()
{
}
LuaWrapper::~LuaWrapper()
{
std::cout << "~LuaWrapper Called" << std::endl;
}
void LuaWrapper::RunFuncWithSharedClassParam(
const SharedClass& shared_class)
{
sol::function FuncWithSharedClassParam = GetFunction("C:\\Users\\Omega\\source\\repos\\TestingSolution\\x64\\Debug\\LuaFile.lua", "FuncWithSharedClassParam");
if (FuncWithSharedClassParam)
{
FuncWithSharedClassParam(shared_class);
}
}
// Returns true if script loaded
bool LuaWrapper::LoadScriptIfNeeded(
const std::string& file_path)
{
if (!file_path.empty() && m_lua_states.find(file_path) == m_lua_states.end())
{
m_lua_states.emplace(file_path, sol::state());
m_lua_states[file_path].open_libraries(sol::lib::base);
RegisterUserTypes(m_lua_states[file_path]);
sol::protected_function_result result = m_lua_states[file_path].safe_script_file(file_path, &sol::script_pass_on_error);
if (!result.valid())
{
sol::error err = result;
std::string what = err.what();
std::cout << "LuaWrapper::LoadScriptIfNeeded()" << "Failed to load script:" << file_path << " - " << what << std::endl;
return false;
}
return true;
}
return false;
}
void LuaWrapper::RegisterUserTypes(
sol::state& lua_state)
{
lua_state.new_usertype<SharedClass>(
// Lua Class Name
"SharedClass",
// Member Function Binding
"Print", &SharedClass::Print);
}
sol::function LuaWrapper::GetFunction(
const std::string& file_path,
const std::string& function_name)
{
if (!function_name.empty())
{
LoadScriptIfNeeded(file_path);
LuaStates::const_iterator it = m_lua_states.find(file_path);
if (it != m_lua_states.end() && it->second[function_name].valid())
{
sol::function func = it->second[function_name];
return func;
}
}
return NULL;
}
SharedClass.h
#pragma once
class SamplePtr;
#include <string>
class SharedClass
{
public:
SharedClass(
const int id,
const std::string name);
~SharedClass();
void Print() const;
private:
const int m_id;
const SamplePtr* m_ptr;
// Don't create copies, only one instance of this specific object (with this m_id) can exist for the entire program.
SharedClass() = delete;
// Unfortunately, Lua/Sol is using this to copy (commenting out causes compile errors)
//SharedClass(const SharedClass& rhs) = delete;
SharedClass& operator=(const SharedClass& rhs) = delete;
};
SharedClass.cpp
#include "SharedClass.h"
#include "SamplePtr.h"
#include <string>
#include <iostream>
SharedClass::SharedClass(
const int id,
const std::string name) :
m_id(id),
m_ptr(new SamplePtr(name))
{
}
SharedClass::~SharedClass()
{
std::cout << "~SharedClass Called" << std::endl;
delete m_ptr;
}
void SharedClass::Print() const
{
std::cout << "Shared Classs ID: " << std::to_string(m_id) << " (" << m_ptr->m_name << ")" << std::endl;
}
SamplePtr.h
#pragma once
#include <string>
class SamplePtr
{
public:
SamplePtr(
const std::string& name);
const std::string m_name;
private:
SamplePtr() = delete;
SamplePtr(const SamplePtr& rhs) = delete;
SamplePtr& operator=(const SamplePtr& rhs) = delete;
};
SamplePtr.cpp
#include "SamplePtr.h"
SamplePtr::SamplePtr(
const std::string& name) :
m_name(name)
{
}
Main.cpp
#include <iostream>
#include "LuaWrapper.h"
#include "SharedClass.h"
int main()
{
// Once created, this object cannot be modified (const).
const SharedClass* sample0 = new SharedClass(0, "Ptr0");
// Create lua in it's own scope, so it's deleted.
{
LuaWrapper lua;
lua.RunFuncWithSharedClassParam(*sample0);
}
// Try to access sample0's pointer and it's deleted at this point (via the LuaWrapper deletion)...
sample0->Print();
}
LuaFile.lua
function FuncWithSharedClassParam(shared_class)
shared_class:Print();
end
I received a response from the Sol developer, https://github.com/ThePhD/sol2/issues/1340.
Pretty much just need to pass in the pointer for no copy!

Self/own implementation of smart pointers

I'm trying to code my own implementation of shared pointers (for fun/challenge) but I hit a dead end after I cannot make the constructor accept any (auto) type of pointer variable. The problem is, for now I can only make my own smart pointer points to a certain data-type (class P) but I want it to be able to point to any data type however the problem is I need to specify the data type in the constructor arguments.
Code:
#include <iostream>
#include <memory>
class P //dummy class
{
int x;
public:
P() : x(42) {}
~P() {}
void print()
{
std::cout<<"Address = "<< this << "\n";
}
};
class P2 //dummy class 2
{
public:
P2() {}
~P2() {}
void print()
{
std::cout<<"Address = "<< this << "\n";
}
};
class SmartP
{
P *ptr;
public:
SmartP(P *p) : ptr(p) {}
~SmartP()
{
delete ptr;
}
P& operator* ()
{
return *ptr;
}
P* operator-> ()
{
return ptr;
}
};
void rawPointer()
{
P *p(new P);
p->print();
delete p; //when removed, next allocated address will be different
}
void smartPointerOwn()
{
SmartP spo(SmartP(new P));
//This should also work but currently it does not: SmartP spo(SmartP(new P2));
spo->print();
//Do not need a delete
}
void smartPointer()
{
std::unique_ptr<P> sp(new P);
sp->print();
//Do not need a delete
}
int main()
{
rawPointer();
smartPointerOwn();
smartPointer();
std::cin.get(); //Prevent exiting console prematurely
return 0;
}
Thanks!
here some basic example to help start you off. Like already mentioned in the comments you should first check some existing smart pointer implementations.
This example is very incomplete - for ex. the reference counting is missing (if shared pointer wanted). But it gives you an idea. I hope it helps a little bit.
#include <iostream>
using namespace std;
template <typename T>
class SmartP {
public:
SmartP() : p{nullptr} {}
SmartP(T* pp) : p{pp} {}
~SmartP() { delete p; }
// dereferencing operators
friend T& operator*(const SmartP<T>& sp) { return *(sp.p); }
T& operator->() const { return *p; }
// get the raw pointer
T* get() const { return p; }
private:
T* p;
};
int main() {
SmartP<int> p{new int{3}};
cout << *p << endl;
*p = 4;
cout << *p << endl;
}

vector push back clarifying

I can't figure out how push_back(const value_type& val) exactly works, in docs it says about val that
val is Value to be copied (or moved) to the new element ...
How it can be copied when it takes val by reference ?
Will that copying ever call the copy constructor of val ?
and what's exactly happening here ?
#include <iostream>
#include <vector>
using namespace std;
struct x
{
x(int v = 0) : v(v) {}
int v;
};
vector<vector<x>> parts;
void fillParts()
{
vector<x> values = { x(1), x(2), x(3) };
parts.push_back(values);
}
int main()
{
fillParts();
parts[0][0].v = -123;
cout << parts[0][0].v; // -123
return 0;
}
this runs with no erros,
is parts[0] is a reference to local vector values or a copy ?
if it is a reference shouldn't it at least give some warnings saying that your accessing and modifying local objects of freed stack ?
How it can be copied when it takes val by reference?
Think of a copy constructor.
It takes parameter by reference, and it performs copying perfectly.
class Bar
{
public:
Bar(const Bar & rhs); // by reference, to copy.
};
Will that copying ever call the copy constructor of val ?
Copy operation uses copy constructor.
You can actually see if it's copied, or moved by providing user-defined constructors.
struct x
{
public:
x(const x & rhs)
{
// Some copy operation.
std::cout << "Copied" << std::endl;
}
x(x && rhs)
{
// Some move operation.
std::cout << "Moved" << std::endl;
}
};
You can try this
class A
{
public:
A() {}
A(const A&) { cout << "copy cons" << endl; }
A& operator= (A &&) { cout << "move" << endl; };
A& operator= (const A &) { cout << "copy" << endl; };
};
vector<A> parts;
void fillParts()
{
A a;
parts.push_back(a);
}
int main()
{
fillParts();
return 0;
}
I got copy cons called in both debug and release builds.

dereferencing iterator of STL set

I'm having a problem with inheriting from STL set (i think):
Here is class Prime:
class Prime : public set<A> {
private:
// private data members.
public:
// C'tor...
void printParticularA(const int& id);
}
Here is class A:
class A : public List<B>{
private:
// data members.
int id;
public:
// C'tor
A(const A& copy) : List<B>(copy), //copy data members
{ // validate data and throw exceptions if needed. };
bool operator< (const A& rhs) const{
return id < rhs.id;
}
void printReport() const {
for(const B& item : *this){ item.print(); }
}
}
now here is the problem. in the next function i want to print a particular A object in the set:
void Prime::printParticularA(const int& id) {
find(AFinder(id))->printReport();
}
i also tried this:
void Prime::printParticularA(const int& id) {
*(find(AFinder(id))).printReport();
}
note: assume that class B has print() method.
note2: AFinder is a class for making dummy A objects using only the id data.
the problem is that when 'find' finds the objects it returns const_iterator (because every object in set is const), and when i dereference it i get a copy of the object (??) but the list of B inside it is empty!
this happens also for the '->' version.
now i know that set doesn't allow me to change the objects but i do not intend to change the object (as you can see in the declaration of printReport member function).
i appreciate any help in this!
EDIT: thanks everyone, you have helped me a lot especially learning what not to do.
I solved the problem and it wasn't in set, list nor any of my classes presented here.
my mistake was in understanding the question i was given (yes this is my homework assignment, i'm still new to c++).
sorry if you feel i have wasted your time.
i hope that i can learn from all of your experience and someday help others!
in short, THANKS!! :)
Your code is pretty much messed up all around. And the problem does not look tied directly to set or iterator, but general bad things done.
For starters make your op< const and delete the copy ctor for good -- the stock one shall work fine. Use internal find of set to search and look if it found an item.
All that will likely make your described problem gone, if not, post a complete compileable example with proper text of what you see and what you expect.
Your code really violate many rules of C++. Why don't you try smth like this:
#include <iostream>
#include <list>
#include <map>
using namespace std;
class SimpleInt {
public:
int data_;
SimpleInt(const int data): data_(data) {};
void print() const {cout << data_ << " ";};
};
template <typename T>
class A {
private:
// private data members.
public:
list<T> list_of_B_; // this is for simlicity. Make getters as you need
const int id_; // delete it or copy to map. You sholdn't change it.
A(int id) : list_of_B_(), id_(id) {}
A(const A<T>& copy) : list_of_B_(copy.list_of_B_), id_(copy.id_) {} //copy data members
A(A<T>&& copy) : list_of_B_(::std::move(copy.list_of_B_)), id_(copy.id_) {} //move data members
void printReport() const {
for(const T& item : list_of_B_){ item.print(); }
}
};
template <typename T>
class Prime {
private:
// private data members.
public:
// The main difference with your source
map<int, T> map_of_A_; // this is for simlicity. Make getters as you need
// C'tor...
void printParticularA(const int& id) {
auto it = map_of_A_.find(id);
if (it != map_of_A_.end())
it->second.printReport();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
typedef A<SimpleInt> ASimpled;
Prime<ASimpled> prime;
ASimpled a(1);
a.list_of_B_.push_back(SimleInt(1));
a.list_of_B_.push_back(SimleInt(2));
a.list_of_B_.push_back(SimleInt(3));
ASimpled b(2);
b.list_of_B_.push_back(SimleInt(10));
b.list_of_B_.push_back(SimleInt(20));
b.list_of_B_.push_back(SimleInt(30));
prime.map_of_A_.insert(make_pair(a.id_, a));
prime.map_of_A_.insert(make_pair(b.id_, b));
prime.printParticularA(2);
return 0;
}
Although you haven't included the implementation of List the problem is likely there. To be more precise the begin() and end() member functions of List may be broken. Chances are the values they return are identical (or invalid) resulting in the range based for loop doing nothing. This of course is based on your set::find is returning a valid iterator and not the end iterator.
The following example is a modification of the code in your question. It uses std::list instead of List and doesn't use AFinder since you haven't included the code for it.
#include <set>
#include <list>
#include <iostream>
struct B
{
int id_;
explicit B(int id) : id_(id) {}
void print() const
{
std::cout << "B::id = " << id_ << std::endl;
}
};
class A : public std::list<B>
{
public:
explicit A(int id) : id_(id) {}
bool operator<(const A& rhs) const
{
return id_ < rhs.id_;
}
bool operator==(const A& other) const
{
return id_ == other.id_;
}
void printReport() const
{
for(auto& item : *this)
{
item.print();
}
}
private:
// data members.
int id_;
};
class Prime : public std::set<A>
{
public:
void printParticularA(const int& id)
{
std::cout << "finding " << id << std::endl;
auto el = find(A(id));
if(el == cend())
{
std::cout << "not found" << std::endl;
}
else
{
find(A(id))->printReport();
}
std::cout << "done finding " << id << std::endl;
}
};
int main()
{
Prime p;
A a1(1);
a1.push_back(B(1));
a1.push_back(B(2));
a1.push_back(B(3));
p.insert(a1);
A a2(2);
a2.push_back(B(4));
a2.push_back(B(5));
a2.push_back(B(6));
p.insert(a2);
p.printParticularA(1);
p.printParticularA(2);
// doesn't exit
p.printParticularA(3);
}
This produces the following output.
finding 1
B::id = 1
B::id = 2
B::id = 3
done finding 1
finding 2
B::id = 4
B::id = 5
B::id = 6
done finding 2
finding 3
not found
done finding 3