Need help implementing a SmartPointer - c++

I'm having trouble implementing a smart pointer in C++ for an assignment.
My code is supposed to create two SmartPointers. The first points to 1 and the second initially points to 3 but is changed to 10. My code should print out
intOne: 1
intTwo: 10
but instead it prints out
intOne: 10
intTwo: 4919984
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <exception>
using namespace std;
template <typename T>
class SmartPointer
{
public:
SmartPointer(T in)
{
try
{
if(in<0)
{
throw "SmartPointer does not handle negative numbers";
}
T * val = &in;
this->data = val;
}
catch(exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
}
~SmartPointer()
{
delete data;
}
T getValue();
void setValue(T val);
private:
T*data;
};
template <typename T> T SmartPointer<T>::getValue()
{
return *this->data;
}
template <typename T> void SmartPointer<T>::setValue(T val)
{
if(val<0)
{
throw "SmartPointer does not handle negative numbers";
}
this->data = &val;
}
int main()
{
SmartPointer<int> intOne(1);
SmartPointer<int> intTwo(3);
intTwo.setValue(10);
cout<<"intOne: "<<intOne.getValue()<<endl;
cout<<"intTwo: "<<intTwo.getValue()<<endl;
}

Your constructor takes a T by value and then attempts to set the internal pointer to the local copy of the value. It should take the address of a T instead.
Your exception stuff is unnecessary, since the class doesn't even know what type is T, so it could be some type that does not have a comparison operator with an int. Even if you do need to throw exceptions, they should be caught in main(), since nobody expects a constructor to print error messages to the screen. throw "message" is wrong, since you're trying to throw an instance of const char*. Instead, call the constructor of one of the standard exceptions like throw domain_error("message").
Using this-> does not really do anything other than make it slower to type.
In case you didn't know, using endl flushes the buffer. If you don't need it, use '\n'.
The fixed code:
//#include <stdio.h> Why?
//#include <stdlib.h>
#include <iostream>
#include <exception>
using namespace std;
template<typename T>
class SmartPointer
{
public:
SmartPointer(T *in);
~SmartPointer();
T getValue();
void setValue(const T &val);
private:
T *data;
};
template<typename T> SmartPointer<T>::SmartPointer(T *in) //Moved implementation outside of class declaration
{
//Completely unnecessary exception stuff
data = in; //this-> is unnecessary
}
template<typename T> SmartPointer<T>::~SmartPointer()
{
delete data;
}
template<typename T> T SmartPointer<T>::getValue()
{
return *data;
}
template<typename T> void SmartPointer<T>::setValue(const T &val)
{
//More unnecessary exception stuff
*data = val;
}
int main()
{
SmartPointer<int> intOne(new int); //The constructor should take a pointer for the object to store instead of an value
SmartPointer<int> intTwo(new int);
intOne.setValue(1);
intTwo.setValue(10);
cout << "intOne: " << intOne.getValue() << '\n'; //endl flushes the buffer, kind of unnecessary here
cout << "intTwo: " << intTwo.getValue() << '\n'; //since it gets flushed upon the program exiting anyways
}

Related

Error: "invalid operands to binary expression" while checking stringstream type

For academic reasons I am trying to build a Generic Wrapper.
This one owns one method to convert the Wrapper to string: to_string.
In order to be able to make the job when wrapped types are complex or custom, the class can take a lambda to "stringify" the value.
Because the lambda can be null, a check must be done to build the resulting string by the "natural way" or using the lambda.
But as soon as I wrap a complex type (eg: a struct), the pre-compiler (Xcode dialecte: GNU++17) reports an error.
Let's see the code:
#include <iostream>
#include <sstream>
#include <any>
using namespace std;
template <typename T>
class Wrapper {
using Stringer = string(*)(any);
Stringer stringer;
public:
T value;
Wrapper(T value): value(value), stringer(nullptr) {}
Wrapper(T value, Stringer stringer): value(value), stringer(stringer) {}
void setValue(T value) { this->value = value; }
string to_string() const {
stringstream buffer;
buffer << "(vtw)";
if (stringer == nullptr) {
buffer << value; // << Invalid operands to binary expression ('std::stringstream' (aka 'basic_stringstream<char>') and 'const Coord')
} else {
buffer << stringer(value);
}
return buffer.str();
}
};
int main(int argc, const char * argv[]) {
using Coord = struct {int x; int y; };
auto coord = new Wrapper((Coord){-105,245},
[](any value)->string{ Coord value_ = any_cast<Coord>(value); stringstream buffer; buffer << value_.x << "," << value_.y; return buffer.str(); }
);
cout << coord->to_string() << endl;
return 0;
}
Any ideas how to work around it?
buffer << value; must be valid, which it is not for your unnamed Coord. You could add a constexpr-if check to see if it supports streaming:
string to_string() const {
ostringstream buffer;
buffer << "(vtw)";
if (stringer == nullptr) {
if constexpr(can_ostream_v<T>) { // test here
buffer << value;
}
} else {
buffer << stringer(value);
}
return buffer.str();
}
The can_ostream_v type trait used above could look like this:
#include <type_traits>
#include <utility>
template<class T>
struct can_ostream {
static std::false_type test(...);
template<class U>
static auto test(U) -> decltype(std::declval<std::ostream&>() << std::declval<U>(),
std::true_type{});
static constexpr bool value = decltype(test(std::declval<T>()))::value;
};
template<class T>
inline constexpr bool can_ostream_v = can_ostream<T>::value;
Demo

Is there a template generic call operator for any posible case?

I want to create a smart pointer that in case it have a function (static, lambda or member function) it can be called using "operator()", this is my first approach:
#include <cstdio>
#include <type_traits>
#include <iostream>
#include <string>
using namespace std;
template <typename Class>
struct TestPtrImpl {
Class* ptr;
TestPtrImpl(Class* ptr) : ptr(ptr) { }
template <typename... Args>
inline auto operator()(Args... args) {
if (ptr) {
if constexpr (std::is_invocable<Class, Args...>::value) {
return ptr(args...);
}
}
}
};
template <typename TClass>
TestPtrImpl<TClass> TestPtr(TClass* ptr) { return TestPtrImpl<TClass>(ptr); }
int test(string b, int a = 3) {
cout << "Hello World" << b << a << endl;
return 0;
}
int main() {
cout << TestPtr(test)("h",5) << endl;
return 0;
}
But when I try to call TestPtr(test) with only the string parameter it doesn't call the function (so default parameters seems to not work with "std::is_invocable", is there any other solution that can be used in any function case?
And, Is there an implementation of "->" that can be safe-called (like for example null conditional "?" operator in C#)?

How to pass functions as parameters within a class?

I am trying to pass my print function as a paramater through my inordertraversal class which belongs to a templated binarySearchTree. whenever I define these functions within main the program works fine but whenever i try to encapsulate them I get a error:
"expected primary-expression before '&' token"
This is the code that works
void print(classdatatype& x);
int main()
{
binarySearchTree<classdatatype> tree;
tree.inorderTraversal(print);
return 0;
}
void print(classdatatype& x) { cout << x << " "; }
The declaration of my inordertraveral templated class is
template <class elemType>
void binarySearchTree<elemType>::inorderTraversal(void (*visit)(elemType& item))
I can show the rest of the code if needed but this all works just fine
Once I move these functions into my class it looks like this
(the declarations for print and the binarySearchTree are in the .cpp same as they are declared above)
void bst::printfunctions(classdatatype& x)
{
tree.inorderTraversal(print(classdatatype & x)); //error here
}
void bst::print(classdatatype& x)
{
cout << x << " ";
}
The error is to do within the brackets of print, I have tried many different things but to me this is the correct declaration; therefore I don't know why it's not working.
Any advice would be greatly appreciated.
EDIT: print is a function pointer to print the details of classdatatype which is stored inside a binary search tree.
EDIT2: minimal reproducible example.
Data types are as they are and not like in the above example. This is as basic as I could make this and I ended up getting another error which I couldn't resolve but for the purpose of this example it doesn't matter and should be ignored.
main() is included but is minimal and may not serve its purpose but the problem doesn't lie here anyway.
main()
#include <iostream>
#include "windlogtype.h"
using namespace std;
int main()
{
windlogtype wind;
ifstream infile("data.txt");
//for purose of this data is one integer value
infile >> wind;
//do something
//main purpose is to get input
return 0;
}
class windlogtype
#include "windlogtype.h"
windlogtype::windlogtype() { }
windlogtype::windlogtype(int i) { num = i; }
int windlogtype::Getnumber() const { return num; }
void windlogtype::Setnumber(int i) { num = i; }
ostream operator<<(ostream& os, const windlogtype& w)
{
os << w.Getnumber() << '\n';
return os;
}
#ifndef WINDLOGTYPE_H
#define WINDLOGTYPE_H
#include <iostream>
using namespace std;
class windlogtype
{
public:
windlogtype();
windlogtype(int i);
int Getnumber() const;
void Setnumber(int i);
private:
int num;
};
ostream operator<<(ostream& os, const windlogtype& w);
#endif // WINDLOGTYPE_H
class binarySearchTree
#include <iostream>
#include <assert.h>
using namespace std;
template <class elemType> struct binaryTreeNode
{
elemType info;
binaryTreeNode<elemType>* llink;
binaryTreeNode<elemType>* rlink;
};
template <class elemType> class binarySearchTree
{
public:
const binarySearchTree<elemType>& operator=(const binarySearchTree<elemType>&);
void inorderTraversal(void (*visit) (elemType&));
binarySearchTree();
~binarySearchTree();
binaryTreeNode<elemType>* root;
private:
void inorder(binaryTreeNode<elemType>* p, void (*visit) (elemType&));
};
template <class elemType> binarySearchTree<elemType>::binarySearchTree() {
root = NULL;
}
template <class elemType> void binarySearchTree<elemType>::inorderTraversal(void (*visit) (elemType& item))
{
inorder(root, *visit);
}
template <class elemType> void binarySearchTree<elemType>::inorder(binaryTreeNode<elemType>* p, void (*visit) (elemType& item))
{
if (p != NULL)
{
inorder(p->llink, *visit);
(*visit)(p->info);
inorder(p->rlink, *visit);
}
}
class bst
#ifndef BST_H
#define BST_H
#include "binarySearchTree.h"
#include "windlogtype.h"
using namespace std;
class bst
{
public:
bst();
void InsertTree(windlogtype& newwind);
void printfunctions(windlogtype& x);
binarySearchTree<windlogtype>& GetTree();
void print(windlogtype& x);
private:
binarySearchTree<windlogtype> treeRoot;
};
#endif // BST_H
#include "bst.h"
bst::bst(){/*ctor*/ }
binarySearchTree<windlogtype>& bst::GetTree() { return treeRoot; }
void bst::print(windlogtype& x) { cout << x << " "; }
void bst::printfunctions(windlogtype& x)
{
treeRoot.inorderTraversal(print(windlogtype & x)); // error lies here
}
The
void bst::print(classdatatype& x) // is a member function
and
void print(classdatatype& x); // is a free function.
Hence the function pointers to hold them will be also different.
The OP has mentioned in the comments, that he/she wants to pass the member function print() from bst class to member functioninorderTraversal() of binarySearchTree<elemType> class. In that case passing the member-function is not sufficient, in addition to that the instance of the class to which the print function will be called also should be passed.
The Lambda function can come in handy to simplify this by capturing the instance of bst class and pass to the inorderTraversal() of the binarySearchTree class.
That means, inside template <class elemType> class binarySearchTree provide:
template<typename Callable>
void inorderTraversal(Callable visit)
{
inorder(root, visit); // simply pass visit further
// or avoid coping by warapping std::cref(): i.e. inorder(root, std::cref(visit));
}
template<typename Callable>
void inorder(binaryTreeNode<elemType>* p, Callable visit)
{
if (p != NULL)
{
inorder(p->llink, visit); // or inorder(root, std::cref(visit));
visit(p->info); // call directly with parameter
inorder(p->rlink, visit); // or inorder(root, std::cref(visit));
}
}
Inside the bst class
void printfunctions(windlogtype& x)
{
// lambda captures the instance by copy
const auto printThisLogType = [this](windlogtype & x)->void { this->print(x); };
treeRoot.inorderTraversal(printThisLogType); // pass the callable lambda
}
Here is compiling code: https://godbolt.org/z/jhCnPs
PS: The other error was from operator<< of windlogtype class where you missed to return the reference of std::ostream.
To be honest, you could have made a further simpler minimal code, by replacing windlogtype with int and showing the defenitions of the member function next to the declaration. That would make the code to read easily.

C++ is it possible to have a container of specialized templates objects with different types parameters?

I have a templated class Parameter which can (or must) be specialized.
I want to put all my parameters in a container.
How to do this if my parameters are instanciated with different types?
In the class Container, I would like to have a vector<Parameter*> from different types (int, double, ...) or something equivalent which seems to not possible.
If the Parameter class is derived from a base class, then The Container can declare the vect as vector<Base*>. But in this case, we can do nothing specific in Container::foo.
Below is my source example. One of my parameters is a QString which is not compatible with ostream.
Thanks for your comments.
#include <QString>
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
#define P(a) cout << #a << ":" << a << endl
/*
class Base {
};
*/
template<typename T> class Parameter /*: public Base */ {
private:
T val;
public:
void setVal(const T &val) {
this->val = val;
}
const T &getVal() {
return val;
}
string getFoo() {
stringstream s;
s << val;
return s.str();
}
};
template<>
string Parameter<QString>::getFoo() {
stringstream s;
s << val.toStdString();
return s.str();
}
class Container {
public:
void push_back(Parameter *base) {
vect.push_back(base);
}
void foo() {
/* do something with the parameters */
}
private:
vector<Parameter*> vect;
};
int main() {
Parameter<int> pi;
Parameter<QString> ps;
pi.setVal(10);
ps.setVal("QString");
P(pi.getVal());
P(ps.getVal().toStdString());
P(pi.getFoo());
P(ps.getFoo());
Container container;
container.push_back(&pi);
container.push_back(&ps);
}
Many thanks to you comments. I will follow your advice and use boost::any.
Here is the updated version :
#include <boost/any.hpp>
#include <QString>
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
#define P(a) cout << #a << ":" << a << endl
template<typename T> class Parameter {
private:
T val;
public:
void setVal(const T &val) {
this->val = val;
}
const T &getVal() {
return val;
}
string getFoo() {
stringstream s;
s << val;
return s.str();
}
};
template<>
string Parameter<QString>::getFoo() {
stringstream s;
s << val.toStdString();
return s.str();
}
class Container {
public:
void push_back(boost::any base) {
vect.push_back(base);
}
void foo() {
cout << "do something with the parameters\n";
for (vector<boost::any>::iterator i = vect.begin(); i != vect.end(); ++i) {
boost::any a = (*i);
if (a.type() == typeid(Parameter<int>*)) {
Parameter<int> *ai = boost::any_cast<Parameter<int> *>(a);
cout << ai->getFoo() << endl;
} else if (a.type() == typeid(Parameter<QString>*)) {
Parameter<QString> *aq = boost::any_cast<Parameter<QString> *>(a);
cout << aq->getFoo() << endl;
} else {
cout << "unknown type:" << a.type().name() << endl;
}
}
}
private:
vector<boost::any> vect;
};
int main() {
Parameter<int> pi;
Parameter<QString> ps;
pi.setVal(10);
ps.setVal("QString");
P(pi.getVal());
P(ps.getVal().toStdString());
P(pi.getFoo());
P(ps.getFoo());
Container container;
container.push_back(&pi);
container.push_back(&ps);
container.foo();
}
The correct solution is to write good enough interface for the Base class so that you can do everything you need to do:
class Base {
public:
virtual void *GetVal() const=0;
virtual void SetVal(void *ptr)=0;
virtual std::string Type() const=0;
virtual std::string GetAsString() const=0;
};
While this might not be what you want, it still allows passing values from one parameter to the next. Once you want the actual value, you do need to know the type on compile-time. Switch-case for the type might help with making it runtime.
You could use Boost.Any which can hold any type of data. You would then use boost::any_cast<> to convert the object back to the correct type.
Other than that, you'll have to go for the base class approach, but as you mentioned, it could be hard to then make Container::foo do anything useful.
One way you could solve this problem is to have all your foo functions take a string as a parameter, then each specific implementation of the function would parse that string and convert it to the correct type.
Edit: Boost.Any example:
#include <iostream>
#include <boost/any.hpp>
int main()
{
boost::any param = 89;
// This will fail because `param` is currently holding an int
// not a char
char ch = boost::any_cast<char>(param);
// This works
int i = boost::any_cast<int>(param);
// You can always change the value and type of what
// `param` is holding
param = "example";
}
Every thing inside a container has to be the same type. I have done something similar to your approach where I made a base class that had some useful generic interface and the derived class was templated. The only other way to approach a solution would involve defining a base class function to return a value to indicate the type and then downcasting the base.

Can smart pointers selectively hide or re-direct function calls to the objects they are wrapping?

I'm working on a project where certain objects are referenced counted -- it's a very similar setup to COM. Anyway, our project does have smart pointers that alleviate the need to explicitly call Add() and Release() for these objects. The problem is that sometimes, developers are still calling Release() with the smart pointer.
What I'm looking for is a way to have calling Release() from the smart pointer create a compile-time or run-time error. Compile-time doesn't seem possible to me. I thought I had a run-time solution (see code below), but it doesn't quite compile either. Apparently, implicit conversion isn't allowed after using operator->().
Anyway, can anyone think of a way to accomplish what I'm trying to accomplish?
Many thanks for your help!
Kevin
#include <iostream>
#include <cassert>
using namespace std;
class A
{
public:
void Add()
{
cout << "A::Add" << endl;
}
void Release()
{
cout << "A::Release" << endl;
}
void Foo()
{
cout << "A::Foo" << endl;
}
};
template <class T>
class MySmartPtrHelper
{
T* m_t;
public:
MySmartPtrHelper(T* _t)
: m_t(_t)
{
m_t->Add();
}
~MySmartPtrHelper()
{
m_t->Release();
}
operator T&()
{
return *m_t;
}
void Add()
{
cout << "MySmartPtrHelper::Add()" << endl;
assert(false);
}
void Release()
{
cout << "MySmartPtrHelper::Release()" << endl;
assert(false);
}
};
template <class T>
class MySmartPtr
{
MySmartPtrHelper<T> m_helper;
public:
MySmartPtr(T* _pT)
: m_helper(_pT)
{
}
MySmartPtrHelper<T>* operator->()
{
return &m_helper;
}
};
int main()
{
A a;
MySmartPtr<A> pA(&a);
pA->Foo(); // this currently fails to compile. The compiler
// complains that MySmartPtrHelper::Foo() doesn't exist.
//pA->Release(); // this will correctly assert if uncommented.
return 0;
}
You can't do it - once you've overloaded the operator -> you're stuck - the overloaded operator will behave the same way reardless of what is rightwards of it.
You could declare the Add() and Release() methods private and make the smart pointer a friend of the reference-counting class.
operator-> has to return a pointer or an object which itself supports operator->. It can be recursive. What you can't do is to have operator-> behave differently based on what appears on the right hand side of the ->.
I can't think of any approach that doesn't involve somehow replicating the interfaces of your pointed-to objects, or require you to create objects publicly derived from your pointed to objects with Add and Release hidden and made private in the derived class and using a Base* pBase = pDerived; pBase->Add(); trick to call add and release from the smart pointer.
i got it to work by changing the overloaded operator in MySmartPtr and adding an overload operator in MySmartPtrHelper:
#include <iostream>
#include <cassert>
using namespace std;
class A
{
public:
void Add()
{
cout << "A::Add" << endl;
}
void Release()
{
cout << "A::Release" << endl;
}
void Foo()
{
cout << "A::Foo" << endl;
}
};
template <class T>
class MySmartPtrHelper
{
T* m_t;
public:
MySmartPtrHelper(T* _t)
: m_t(_t)
{
m_t->Add();
}
~MySmartPtrHelper()
{
m_t->Release();
}
operator T&()
{
return *m_t;
}
T* operator->()
{
return m_t;
}
void Add()
{
cout << "MySmartPtrHelper::Add()" << endl;
assert(false);
}
void Release()
{
cout << "MySmartPtrHelper::Release()" << endl;
assert(false);
}
};
template <class T>
class MySmartPtr
{
MySmartPtrHelper<T> m_helper;
public:
MySmartPtr(T* _pT)
: m_helper(_pT)
{
}
T* operator->()
{
return m_helper.operator->();
}
};
int main()
{
A a;
MySmartPtr<A> pA(&a);
pA->Foo();
//pA->Release(); // this will correctly assert if uncommented.
return 0;
}
Output:
macbook-2:~ $ ./a.out
A::Add
A::Foo
A::Release
I suggest you use something like the following code.
What you want is not possible unless you are willing to add a small constraint : objects must be copy-constructible (and you don't mind using this possibility). In this case, inheritance is a good way to go.
#include <iostream>
#include <cassert>
using namespace std;
template <class T>
class MySmartPtrHelper : public T
{
public:
MySmartPtrHelper(T* _t)
: m_t(*_t)
{
delete _t;
((T*) this)->Add();
}
~MySmartPtrHelper()
{
((T*) this)->Release();
}
void Add()
{
cout << "MySmartPtrHelper::Add()" << endl;
//will yield a compile-time error
BOOST_STATIC_ASSERT(false)
}
void Release()
{
cout << "MySmartPtrHelper::Release()" << endl;
//will yield a compile-time error
BOOST_STATIC_ASSERT(false)
}
};
template <class T>
class MySmartPtr
{
MySmartPtrHelper<T>* m_helper;
// Uncomment if you want to use boost to manage memory
// boost::shared_ptr<MySmartPtrHelper<T> > m_helper;
public:
MySmartPtr(T* _pT)
: m_helper(new MySmartPtrHelper<T>(_pT))
{
}
MySmartPtrHelper<T>* operator->()
{
return m_helper;
}
};
int main()
{
MySmartPtr<A> pA(new A());
pA->Foo();
//pA->Release(); // this will correctly assert if uncommented.
return 0;
}