I'm trying to create Copy Constructor.
For example, There is a class like :
#include <string>
#include <vector>
using namespace std;
class Test
{
vector<string*> name;
public:
~Test();
Test(const string& name);
Test(const Test& t);
};
Test::Test(const Test& t)
{
for (auto it = t.name.begin(); it != t.name.end(); it++) {
this->name.push_back((*it));
}
}
Test::Test(const string& name)
{
this->name.emplace_back(name);
}
Test::~Test() {
for (auto it = name.begin(); it != name.end(); it++) {
delete (*it);
(*it) = nullptr;
}
}
int main() {
Test t("Hello World!");
Test t2(t);
}
When program is done, then error occured:
Access violation reading location 0xDDDDDDDD
I know that, it is because of t's name has deleted when t2 is called, however I don't know how to deep-copy of the name vector.
Thank you for your help.
In order to make a deep copy, you need to copy what any pointer points to.
Like this:
name.push_back(new string(**it));
You also need to implement the copy assignment operator.
Related
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!
Below is a downsized implementation of a two classes I'm having trouble with.
code:
Here is the base class:
//header
class Script
{
public:
Script(const QString& path, int timeout=10000) :
mPath(path), mTimeout(timeout), script(new QProcess) {}
Script(Script&& s);
Script& operator=(Script&& s);
virtual ~Script();
protected:
QString mPath;
int mTimeout;
QProcess* script;
}
//source
Script::Script(Script&& s) :
mPath(s.mPath), mTimeout(s.Timeout), script(s.script)
{
s.script = nullptr;
}
Script& Script::operator=(Script&& s){
if(&s != this){
delete script;
script = s.script;
s.script = nullptr;
mPath = s.mPath;
mTimeout = s.mTimeout;
}
return *this;
}
Script::~Script() {
delete script;
script = nullptr;
}
From the code snippet above I derive the following class:
//header
class ConfigurationScript : public Script
{
public:
ConfigurationScript(const QString& path);
ConfigurationScript(ConfigurationScript&& s);
ConfigurationScript& operator=(ConfigurationScript&& s);
}
//source
ConfigurationScript::ConfigurationScript(const QString& path) :
Script(path) {}
ConfigurationScript::ConfigurationScript(ConfigurationScript&& s) :
Script(std::move(s)) {}
ConfiguratonScript& ConfigurationScript::operator=(ConfigurationScript&& s) {
if(&s != this){
delete script;
script = s.script;
s.script = nullptr;
mPath = s.mPath;
mTimeout = s.mTimeout;
}
return *this;
}
question:
The move assignment of ConfigurationScript contains duplicate code when you compare it to the move assignment of its base class Script. Can you call the assignment operator of the base class to overcome duplicate code?
For instance is something like this valid?
ConfigurationScript& ConfigurationScript::operator=(ConfigurationScript&& s) {
if(&s != this){
Script::operator=(s);
}
return *this;
}
The return type of Script::operator=(s) is Script, do I need to cast it to a ConfigurationScript?
If the above is valid, I fail to see how it works. Otherwise, is there a way to avoid code duplication?
Yes, it's valid, and you don't need to cast anything.
You're not even using the result of the base op= call, but you know that it is a Script& that refers to the current object. Since you already have a ConfigurationScript& that refers to the current object and has the needed type (i.e. *this), there is nothing more to do.
In fact, this is so natural that you can just let the compiler do it for you:
#include <iostream>
#include <utility>
struct Base
{
Base& operator=(Base&& other)
{
std::cout << "YOLO!\n";
return *this;
}
};
struct Derived : Base
{
/*
// Don't need this
Derived& operator=(Derived&& other)
{
Base::operator=(std::move(other));
return *this;
}*/
/*
// Or even this (though you may need to introduce it
// if you have some other user-declared stuff)
Derived& operator=(Derived&& other) = default;
*/
};
int main()
{
Derived d1, d2;
d2 = std::move(d1);
}
// Output: YOLO!
(live demo)
However I think you probably meant Script::operator=(std::move(s)) to get true movement rather than a copy.
I am new to C++, and I am trying to return the struct declared within a class via char*.
#include<iostream>
using namespace std;
#include <cstring>
class test
{
public:
struct pair
{
int a,b;
};
test(){
pir=new pair;
pir->a=1;
pir->b=2;
}
void readx(char* str)
{
char* str2=new char[sizeof(pair)+1];
str2=reinterpret_cast<char*>(pir);
strncpy(str,str2,sizeof(pair));
}
private:
pair* pir;
};
int main()
{
test t;
char* ptr;
t.readx(ptr);
cout<<*((int*)ptr)<<endl;
cout<<*((int*)ptr+4)<<endl;
return 0;
}
I have tried multiple ways but still failed to return a char* that can be reinterpreted into the struct. Actually the returned char* can only hold the first parameter, losing information about the second parameter, despite that I have used strncpy function. The output of this test code is
1
0
How could I return the everything about struct within the class?
cout<<*((int*)ptr+4)<<endl;
This line should be:
cout<<*((int*)ptr+1)<<endl;
Because you have convert ptr to int *, which +1 means move pointer to next 4 bytes (size of int is 4).
You've got serious problems with your code. If it's really working, it's working only by accident.
Whether it's strncpy or memset you use it doesn't matter too much because you are passing unitialized pointer to the functions which writes to it:
char* ptr;
t.readx(ptr);
Where does ptr point to? It may point almost anywhere and using it as memcpy target is unpredictable. If you are not very unlucky, you will get a segfault/access violation.
Your readx method does some crazy thing:
char* str2 = new char[sizeof(pair)+1];
str2 = reinterpret_cast<char*>(pir);
Here you first alocate some storage and assign its address to str2 then you re-assign it to address of pir. You can never delete[] memory allocated by new[] so you introduce a memory leak.
Constructor of class test allocates memory using new but you don't have corresponding destructor calling delete -> memory leak.
Then there is your ptr+4 problem which was already pointed by the others. Here you can find the code corrected to the point where you can expect it to do what you want.
#include <iostream>
#include <cstring>
using namespace std;
class test
{
public:
struct pair
{
int a, b;
};
test() : pir{ new pair() }
{
pir->a = 1;
pir->b = 2;
}
~test() { delete pir; }
void readx(char* str)
{
memcpy(str, reinterpret_cast<char*>(pir), sizeof(pair));
}
private:
pair* pir;
};
int main()
{
test t;
char* ptr = new char[sizeof(test::pair)];
t.readx(ptr);
cout << *((int*)ptr) << endl;
cout << *((int*)ptr + 1) << endl;
delete[] ptr;
return 0;
}
When you understand the basic issues your code have read about the rule of five. For the test class you would add something like this:
#include <algorithm>
class test
{
//...
test(test const& other) : pir{ new pair() }
{
pir->a = other.pir->a;
pir->b = other.pir->b;
}
test& operator=(test const& other)
{
test copy(other);
swap(*this, copy);
return *this;
}
test(test&& other) noexcept : pir{ nullptr }
{
swap(*this, other);
}
test& operator=(test&& other) noexcept
{
swap(*this, other);
return *this;
}
friend void swap(test& lhs, test& rhs)
{
std::swap(lhs.pir, rhs.pir);
}
};
You are incrementing the int pointer by 4. This points 4 integers ahead. That's not what you want.
cout<<*((int*)ptr+1)<<endl;
That should get you b.
Here is the problem I was thinking about lately. Let's say our interface is a member function that returns object which is expensive to copy and cheap to move (std::string, std::vector, et cetera). Some implementations may compute the result and return a temporary object while others may simply return a member object.
Sample code to illustrate:
// assume the interface is: Vec foo() const
// Vec is cheap to move but expensive to copy
struct RetMember {
Vec foo() const { return m_data; }
Vec m_data;
// some other code
}
struct RetLocal {
Vec foo() const {
Vec local = /*some computation*/;
return local;
}
};
There are also various "clients". Some only read the data, some require an ownership.
void only_reads(const Vec&) { /* some code */ }
void requires_ownership(Vec) { /* some code */ }
Code above composes well, but is not as efficient as it could be. Here are all combinations:
RetMember retmem;
RetLocal retloc;
only_reads(retmem.foo()); // unnecessary copy, bad
only_reads(retloc.foo()); // no copy, good
requires_ownership(retmem.foo()); // copy, good
requires_ownership(retloc.foo()); // no copy, good
What is a good way to fix this situation?
I came up with two ways, but I'm sure there is a better solution.
In my first attempt I wrote a DelayedCopy wrapper that holds either a value of T or a pointer to const T. It is very ugly, requires extra effort, introduces redundant moves, gets in the way of copy elision and probably has many other problems.
My second thought was a continuation-passing style, which works quite well but turns member functions into member function templates. I know, there is std::function, but it has its overhead so performance-wise it may be unacceptable.
Sample code:
#include <boost/variant/variant.hpp>
#include <cstdio>
#include <iostream>
#include <type_traits>
struct Noisy {
Noisy() = default;
Noisy(const Noisy &) { std::puts("Noisy: copy ctor"); }
Noisy(Noisy &&) { std::puts("Noisy: move ctor"); }
Noisy &operator=(const Noisy &) {
std::puts("Noisy: copy assign");
return *this;
}
Noisy &operator=(Noisy &&) {
std::puts("Noisy: move assign");
return *this;
}
};
template <typename T> struct Borrowed {
explicit Borrowed(const T *ptr) : data_(ptr) {}
const T *get() const { return data_; }
private:
const T *data_;
};
template <typename T> struct DelayedCopy {
private:
using Ptr = Borrowed<T>;
boost::variant<Ptr, T> data_;
static_assert(std::is_move_constructible<T>::value, "");
static_assert(std::is_copy_constructible<T>::value, "");
public:
DelayedCopy() = delete;
DelayedCopy(const DelayedCopy &) = delete;
DelayedCopy &operator=(const DelayedCopy &) = delete;
DelayedCopy(DelayedCopy &&) = default;
DelayedCopy &operator=(DelayedCopy &&) = default;
DelayedCopy(T &&value) : data_(std::move(value)) {}
DelayedCopy(const T &cref) : data_(Borrowed<T>(&cref)) {}
const T &ref() const { return boost::apply_visitor(RefVisitor(), data_); }
friend T take_ownership(DelayedCopy &&cow) {
return boost::apply_visitor(TakeOwnershipVisitor(), cow.data_);
}
private:
struct RefVisitor : public boost::static_visitor<const T &> {
const T &operator()(Borrowed<T> ptr) const { return *ptr.get(); }
const T &operator()(const T &ref) const { return ref; }
};
struct TakeOwnershipVisitor : public boost::static_visitor<T> {
T operator()(Borrowed<T> ptr) const { return T(*ptr.get()); }
T operator()(T &ref) const { return T(std::move(ref)); }
};
};
struct Bar {
Noisy data_;
auto fl() -> DelayedCopy<Noisy> { return Noisy(); }
auto fm() -> DelayedCopy<Noisy> { return data_; }
template <typename Fn> void cpsl(Fn fn) { fn(Noisy()); }
template <typename Fn> void cpsm(Fn fn) { fn(data_); }
};
static void client_observes(const Noisy &) { std::puts(__func__); }
static void client_requires_ownership(Noisy) { std::puts(__func__); }
int main() {
Bar a;
std::puts("DelayedCopy:");
auto afl = a.fl();
auto afm = a.fm();
client_observes(afl.ref());
client_observes(afm.ref());
client_requires_ownership(take_ownership(a.fl()));
client_requires_ownership(take_ownership(a.fm()));
std::puts("\nCPS:");
a.cpsl(client_observes);
a.cpsm(client_observes);
a.cpsl(client_requires_ownership);
a.cpsm(client_requires_ownership);
}
Output:
DelayedCopy:
Noisy: move ctor
client_observes
client_observes
Noisy: move ctor
Noisy: move ctor
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
CPS:
client_observes
client_observes
client_requires_ownership
Noisy: copy ctor
client_requires_ownership
Are there better techniques to pass values that avoid extra copies yet are still general (allow returning both temporaries and data members)?
On a side note: the code was compiled with g++ 5.2 and clang 3.7 in C++11. In C++14 and C++1z DelayedCopy doesn't compile and I'm not sure whether it's my fault or not.
There are probably thousands of 'correct' ways. I would favour one in which:
the the method that delivers the reference or moved object is explicitly stated so no-one is in any doubt.
as little code to maintain as possible.
all code combination compile and do sensible things.
something like this (contrived) example:
#include <iostream>
#include <string>
#include <boost/optional.hpp>
// an object that produces (for example) strings
struct universal_producer
{
void produce(std::string s)
{
_current = std::move(s);
// perhaps signal clients that there is something to take here?
}
// allows a consumer to see the string but does not relinquish ownership
const std::string& peek() const {
// will throw an exception if there is nothing to take
return _current.value();
}
// removes the string from the producer and hands it to the consumer
std::string take() // not const
{
std::string result = std::move(_current.value());
_current = boost::none;
return result;
}
boost::optional<std::string> _current;
};
using namespace std;
// prints a string by reference
void say_reference(const std::string& s)
{
cout << s << endl;
}
// prints a string after taking ownership or a copy depending on the call context
void say_copy(std::string s)
{
cout << s << endl;
}
auto main() -> int
{
universal_producer producer;
producer.produce("Hello, World!");
// print by reference
say_reference(producer.peek());
// print a copy but don't take ownership
say_copy(producer.peek());
// take ownership and print
say_copy(producer.take());
// producer now has no string. next peek or take will cause an exception
try {
say_reference(producer.peek());
}
catch(const std::exception& e)
{
cout << "exception: " << e.what() << endl;
}
return 0;
}
expected output:
Hello, World!
Hello, World!
Hello, World!
exception: Attempted to access the value of an uninitialized optional object.
For those of you familiar with the book Accelerated C++, I was writing a solution to problem 14-5 and came across some interesting behavior that I can't explain.
The problem involves using custom string and pointer/reference counter classes to implement a program that can concatenate vectors of strings and create pictures out of them.
Essentially, the part of the program in question is the following:
int main()
{
vec<str> test;
str s;
while(getline(std::cin,s))
{
test.push_back(str(s.begin(),s.end()));
//test.push_back(s); // This line doesn't work here - why?
// Using the above line results in every str in test being
// the empty string
}
// Use the vec<str> to make pictures
}
It seems as though my reference counter isn't working properly when I use the commented line: the result I get is as if every str in test were the empty string.
Here are my implementations of getline and the relevant parts of the str and ptr classes:
str class:
class str
{
friend std::istream& getline(std::istream &is, str &s);
public:
typedef char* iterator;
typedef const char* const_iterator;
typedef size_t size_type;
str() : data(new vec<char>) { }
str(size_type n, char c) : data(new vec<char>(n,c)) { }
str(const char *cp) : data(new vec<char>)
{
std::copy(cp,cp+std::strlen(cp),std::back_inserter(*data));
}
template <class InputIterator>
str(InputIterator b, InputIterator e) : data(new vec<char>)
{
std::copy(b,e,std::back_inserter(*data));
}
// Other str member functions and operators
private:
ptr< vec<char> > data;
};
ptr class:
template <class T>
class ptr
{
public:
void make_unique()
{
if(*refptr != 1)
{
--*refptr;
refptr = new std::size_t(1);
p = p ? clone(p) : 0;
}
}
ptr() : p(0), refptr(new std::size_t(1)) { }
ptr(T* t) : p(t), refptr(new std::size_t(1)) { }
ptr(const ptr &h) : p(h.p), refptr(h.refptr) { ++*refptr; }
ptr& operator=(const ptr &);
~ptr();
T& operator*() const
{
if(p)
{
return *p;
}
throw std::runtime_error("unbound ptr");
}
T* operator->() const
{
if(p)
{
return p;
}
throw std::runtime_error("unbound ptr");
}
private:
T* p;
std::size_t* refptr;
};
template <class T>
ptr<T>& ptr<T>::operator=(const ptr &rhs)
{
++*rhs.refptr;
// free the left hand side, destroying pointers if appropriate
if(--*refptr == 0)
{
delete refptr;
delete p;
}
// copy in values from the right-hand side
refptr = rhs.refptr;
p = rhs.p;
return *this;
}
template <class T>
ptr<T>::~ptr()
{
if(--*refptr == 0)
{
delete refptr;
delete p;
}
}
The vec class is essentially a subset of std::vector. I can supply those details here too, if necessary.
And here is getline:
std::istream& getline(std::istream &is, str &s)
{
s.data->clear();
char c;
while(is.get(c))
{
if(c != '\n')
{
s.data->push_back(c);
}
else
{
break;
}
}
return is;
}
Even though you are counting references correctly, you are still sharing the same pointer between the instances. So getline is modifying the same str object. You need to implement Copy-on-write in str.
Here is what's wrong:
std::istream& getline(std::istream &is, str &s)
{
s.data->clear(); //should make a copy of data first
char c;
while(is.get(c))
{
if(c != '\n')
{
s.data->push_back(c);
}
else
{
break;
}
}
return is;
}
So, you should do:
s.data = ptr(new vec<char>());
instead of clearing the shared instance.
When you call:
test.push_back(s); // This line doesn't work here - why?
now s and a copy of s in test share the same data. During the next iteration of the while loop getline function calls s.data->clear(), which clears data in both s and the copy of s in test.
When you call:
test.push_back(str(s.begin(),s.end()));
the str(s.begin(),s.end()) constructor creates a temp str object with a copy of the data that was in s and pushes that object into test. So now the temp object and the copy in test share the same data, which is a non-shared copy of s. The temp object gets destroyed and the copy in test stays intact.