I wrote a simple template class, which works fine, if the objects are created without using pointers. However if I need to create a pointer to that class object, I get error: invalid conversion from ‘int’ to ‘Logger<int>*’ [-fpermissive]. I am attaching the code below. Any help is appreciated.
Thank you.
#include <iostream>
using namespace std;
template<typename T>
class Logger
{
public:
Logger (const T& d) {data = d;}
void print(){std::cout << "data: " << data << std::endl;}
private:
int data;
};
int main() {
/*
// Works
Logger<int> myLogger(5);
myLogger.print();
*/
Logger<int>* myLogger(5);
myLogger->print();
return 0;
}
If you wanted to allocate a pointer you'd need to use new (and remember to delete it when it is no longer needed so you don't leak it).
Logger<int>* myLogger = new Logger<int>(5);
I don't know what your use case is for doing this, but if you really need to dynamically allocate the object, I'd recommend using smart pointers if you can.
std::unique_ptr<Logger<int>> myLogger = std::make_unique<Logger<int>>(5);
Related
So lets say I have
class A
{
A(std::vector<std::shared_pointer<A>> &a_vec)
{
auto shared_ptr = std::make_shared<A>(*this);
a_vec.pushback<shared_ptr>;
{
};
class B
{
std::vector<std::shared_pointer<A>> a_vector_;
void constructA()
{
created_A = make_shared<A>(a_vector_);
}
}
So Im creating a method for B which creates an A and the A pushes itself to the vector B provides.
And on paper this dependancy works like I expected to, atleast I thought it was until I realised the a_vec.pushback<this*>; is not very dependable.
When I have more code inbetween the push and the shared pointer initialisation as such
A(std::vector<std::shared_pointer<A>> a_vec)
{
auto shared_ptr = std::make_shared<A>(*this);
//insert more code here
a_vec.pushback<shared_ptr>;
{
It seems that the initialisations and other stuff I do in there isn't reflected to the pointer the shared pointer is pointing. Whats the cause of this and is there a way to fix it? Also is there a reason this would be a bad practice to use?
One of the challenges when you are programming in C++ is to understand object lifetime. So it is better to make object creation and destruction as clear as possible.
As I understood your case is to memoize "automagically" all created objects. It is easier to do using "factory method" constructA
#include <iostream>
#include <vector>
#include <memory>
class A
{
public:
A() = default;
};
class B//AInstanceFactory - is a better name
{
std::vector<std::shared_ptr<A>> a_instances;
public:
void constructA()
{
a_instances.push_back(std::make_shared<A>());
}
const std::vector<std::shared_ptr<A>>& getAInstances() {
return a_instances;
}
};
int main()
{
B b;
b.constructA();
std::cout << b.getAInstances().size() << "\n";
b.constructA();
std::cout << b.getAInstances().size() << "\n";
}
[WRONG PATH]
It is possible to make object which aware of shared_ptr/weak_ptr: use template std::enable_shared_from_this.
In that case your code might be following,:
#include <iostream>
#include <vector>
#include <memory>
class A : std::enable_shared_from_this<A>
{
public:
A(std::vector<std::shared_ptr<A>>& a_vec)
{
a_vec.push_back(shared_from_this());//bad_weak_ptr here!!!!
}
};
class B
{
std::vector<std::shared_ptr<A>> a_vector_;
public:
void constructA()
{
auto a_ptr = make_shared<A>(a_vector_);
}
const std::vector<std::shared_ptr<A>>& getAVec() {
return a_vector_;
}
};
int main()
{
B b;
b.constructA();
std::cout << b.getAVec().size() << "\n";
}
BUT it wrong, because underlying weak_ptr is "ready" only after function make_shared is executed, means only after construction call.
Calling shared_from_this or weak_from_this is valid only after make_shared function is executed.
I need to provide a utility function where both memory allocation and object construction take place and the user gets the pointer in return. Similarly, there is a need to provide a utility function for deallocation and destruction also.
Here is what I implemented: (I have not implemented for array type though)
#include <cstdlib> // for malloc
#include <iostream> // for cout
#include <string> // for memset
// C++ class with some initial state x = 10
class SomeClass {
public:
SomeClass() : x(10) {}
int x = 0;
};
template<typename T, typename ... Args>
inline T* MY_MODULE_NEW(Args&&... args) {
// some custom allocator logic here which allocates just raw memory
// for example purpose just use malloc
void *p = malloc(sizeof(T));
memset(p,0,sizeof(T));
T* t = new(p) T(std::forward<Args>(args)...);
return t;
}
template<typename T>
inline void MY_MODULE_DELETE(T* ptr) {
ptr->~T();
// some custom allocator logic here, which deallocates raw memory
// for example purpose just use free
free(ptr);
}
int main() {
SomeClass* sc = MY_MODULE_NEW<SomeClass>();
std::cout << sc->x << std::endl;
SomeClass* sc2 = MY_MODULE_NEW<SomeClass>(*sc);
std::cout << sc2->x << std::endl;
MY_MODULE_DELETE(sc);
MY_MODULE_DELETE(sc2);
}
I have the following concerns:
From the performance point of view, Is this inline function good enough? Can we do better?
Personally I feel MY_MODULE_NEW<SomeClass>(...) syntax is almost similar to the canonical syntax for operator new which is new SomeClass(). Is there any other idiomatic way to achieve the same result?
Thank You!
I am writing an implementation of the Haskell Maybe Monad in C++11.
However I got stuck when I tried to test the code. When I construt a value of the type with the pseudo constructor Just and then try to evaluate it with using the function fromJust (that should just "unpack" the value placed inside the Maybe) the program stops and eventually terminates silently.
So i tried to debug it; here is the output for the code of testMaybe.cpp:
c1
yeih2
value not null: 0xf16e70
I added a couple of print statements to evaluate where the program stops, and it seems to stop at the exact point where I dereference the pointer to return the value. (I have marked it in the code.)
At first I thought that the value in the maybe might have been deconstructed by the time i want to dereference the pointer, which, to my understanding, would result in undefined behaviour or termination. However, I was unable to find the place where that would have happened.
Can you please give me a hint on why this is happening?
testMaybe.cpp:
#include<iostream>
#include "Maybe.hpp"
using namespace std;
using namespace Functional_Maybe;
int main() {
Maybe<string> a{Maybe<string>::Just("hello") };
if(!isNothing(a)) cout << "yeih2 " << fromJust(a) << endl;
return 0;
}
Maybe.hpp
#pragma once
#include<stdexcept>
#include<iostream>
using namespace std;
namespace Functional_Maybe {
template <typename T>
class Maybe {
const T* value;
public:
Maybe(T *v) : value { v } {} //public for return in join
const static Maybe<T> nothing;
static Maybe<T> Just (const T &v) { cout << "c1" << endl; return Maybe<T> { new T(v) }; }
T fromJust() const {
if (isNothing()) throw std::runtime_error("Tried to extract value from Nothing");
cout << "\nvalue not null: " << value << " " << *value << endl;
// ^ stops here
return *value;
}
bool isNothing() const { return value==nullptr; }
~Maybe() { if (value != nullptr) delete value; }
};
template <typename T>
bool isNothing(Maybe<T> val) {
return val.isNothing();
}
template <typename T>
T fromJust(Maybe<T> val) {
return val.fromJust();
}
}
You class template Maybe owns resources (the dynamically allocated T), but does not follow the Rule of Three: the (implicitly defined) copy and move operations do shallow copies only, which leads to use-after-free and double-free problems. You should either implement proper copy and move operations (cosntructors and assignment operators) for your class, or use std::unique_ptr<const T> as the type of value, and remove your manual destructor (thereby following the preferred Rule of Zero).
Side note: have you looked into std::optional (or, in pre-C++17 versions, boost::optional)? They seem to be doing something very similar (or even identical) to your proposed class, and you might want to use them instead (or use them internally in your class if that suits you better). They might even be more efficient, using small object optimisation to avoid dynamic memory allocation in some cases.
I try to create a vector with a pointer (so that everything is stored in/on the heap). I then want to fill the vector with an array of a class. I am thinking about accessing the class by class[i].member... Sadly, it does not work.
If I try this without a vector it works, like in:
tClass *MyClass = new tClass[5]
I am trying this without a specific purpose and only to understand C++ better. Can anyone have a look where I am wrong? Thanks!
Here is the code:
#include "iostream"
#include "vector"
using namespace std;
class tClass
{
private:
int x = 0;
public:
int y = 0;
tClass(){cout << "New" << endl;};
~tClass(){}; //do I need to make a delete here?
int main ()
{
vector<tClass> *MyClass[5];
MyClass = new vector<tClass>[5];
cout << MyClass[3].y << endl;
delete[] MyClass;
}
as others have suggested if you want just a vector of tClass you would do the following
vector<tClass> vectorName (5);
and access it like so
vectorName[3].y;
however if you wanted a vector of tClass pointers you would initialise and acess it like this
vector<tClass*> vectorName(5);
vectorName[3]->y;
edit
this might help you a bit more, this is your code, with comment to help you understand what is going wrong
class tClass
{
private:
int x = 0;
public:
int y = 0;
tClass(){ cout << "New" << endl; };
~tClass(){}; //do I need to make a delete here? //no you dont need to make a delete here as this class contains no "news"
int main()
{
vector<tClass> *MyClass[5]; //use () to give a vector an initial size, [] is only to access a member
//also to have a vector holding pointers, the asterisk needs to be after tClass not before the vector name
MyClass = new vector<tClass>[5];
cout << MyClass[3].y << endl; //discused above
delete[] MyClass; //only needed if a new is used, however you dont need one here, as it will just go out of scope
}
here is you code, but fixed to compile and run with the use of pointers
#include <iostream>
#include <vector>
using namespace std;
class tClass
{
private:
int x = 0;
public:
int y = 0;
tClass(){ cout << "New" << endl; };
};
int main()
{
vector<tClass*> MyClass(5);
cout << MyClass[3]->y << endl;
}
note though that this will give an error as the vector of class pointers are not pointing to any class
I have a class Model:
class Model
{
...
boost::shared_ptr<Deck> _deck;
boost::shared_ptr<CardStack> _stack[22];
};
Deck inherits from CardStack.
I tried to make _stack[0] point to the same thing that _deck points to by going:
{
_deck = boost::shared_ptr<Deck>(new Deck());
_stack[0] = _deck;
}
It seems that the assignment to _deck of _stack[0] results in a copy of _deck being made. (I know this because modifications to _stack[0] do not result in modifications to _deck.) How can I get them to point to the same thing?
Ok - no copy constructor is being called. I have verified this by implementing it and seeing if it gets called - it doesn't.
However - I have a function that operates on CardStack objects:
void TransferSingleCard(CardStack & src, CardStack & dst, Face f)
{
if( !src._cards.empty() )
{
src._cards.back().SetFace(f);
dst.PushCard(src._cards.back());
src._cards.pop_back();
}
}
Now - when I call:
{
TransferSingleCard(*_stack[DECK], _someotherplace, FACEDOWN);
std::cout << *_stack[DECK];
std::cout << *_deck;
}
I get this output (where std::cout on a CardStack will print out the size of that stack):
Num(103) TOP
Num(104) TOP
... so I've concluded (incorrectly?) that _stack[DECK] points to something different.
The Deck
class Deck : public CardStack
{
public:
Deck(int numsuits=2, StackIndex index = NO_SUCH_STACK );
Deck::Deck( const Deck & d);
int DealsLeft() const;
void RecalcDealsLeft();
private:
int _dealsleft;
};
Not clear what you are asking about - consider this code:
#include <iostream>
#include "boost/shared_ptr.hpp"
using namespace std;
struct A {
virtual ~A() {
cout << "destroyed" << endl;
}
};
struct B : public A {
};
int main() {
boost::shared_ptr<B> b( new B );
boost::shared_ptr<A> a;
a = b;
}
Only one "destroy" message appears, indicating that no copy has been made.
This example - derives from #Neil's answer, tries to emulate what you say is happening. Could you check that it works as expected (A and B have the same count) on your system.
Then we could try and modify this code or your code until they match.
#include <boost/shared_ptr.hpp>
#include <iostream>
class A {
public:
virtual ~A()
{
std::cerr << "Delete A" << std::endl;
}
int _count;
void decrement()
{
_count --;
}
};
class B : public A {
public:
virtual ~B()
{
std::cerr << "Delete B" << std::endl;
}
};
int main()
{
boost::shared_ptr<B> b(new B);
b->_count = 104;
boost::shared_ptr<A> a;
a = b;
a->decrement();
std::cerr << "A:" << a->_count << std::endl;
std::cerr << "B:" << b->_count << std::endl;
return 0;
}
EDIT:
So from the comment, we know the original pointers are correct, so now we need to trace.
Either:
log pointers to see when they change.
Use watchpoints in a debugger to see when the pointer changes.
Use a third shared pointer to see which pointer is changed.
Introduce a function that changes both pointers at the same time.
I think the problem is that you're assigning between different types here. boost::shared_ptr is a template and templates are not polymorphic even if the type in them is. So what's happening is that your compiler sees the assignment from boost::shared_ptr<Deck> to boost::shared_ptr<CardStack> and notices that it can make the assignment by calling the copy constructor for CardStack to duplicate the Deck object.
I think what you want the assignment to look like is something like this:
_stack[0] = boost::static_pointer_cast<CardStack>(_deck);
Which will do the conversion the way you expect it to.
I think you may want shared_array for _stack . . . Take a look at the documentation on shared_ptr;from boost.org, specifically:
http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm
"Normally, a shared_ptr cannot
correctly hold a pointer to a
dynamically allocated array. See
shared_array for that usage."
Also, be aware of the T* get() function (not to be used without good reason) which returns the raw pointer being held by the managed pointer (shared_ptr in this case).