Which cast am I using?
I'm trying to cast away const from an object but it doesn't work. But if I use old C-way of casting code compiles. So which casting I'm suppose to use to achieve this same effect? I wouldn't like to cast the old way.
//file IntSet.h
#include "stdafx.h"
#pragma once
/*Class representing set of integers*/
template<class T>
class IntSet
{
private:
T** myData_;
std::size_t mySize_;
std::size_t myIndex_;
public:
#pragma region ctor/dtor
explicit IntSet();
virtual ~IntSet();
#pragma endregion
#pragma region publicInterface
IntSet makeUnion(const IntSet&)const;
IntSet makeIntersection(const IntSet&)const;
IntSet makeSymmetricDifference(const IntSet&)const;
void insert(const T&);
#pragma endregion
};
//file IntSet_impl.h
#include "StdAfx.h"
#include "IntSet.h"
#pragma region ctor/dtor
template<class T>
IntSet<T>::IntSet():myData_(nullptr),
mySize开发者_StackOverflow_(0),
myIndex_(0)
{
}
IntSet<T>::~IntSet()
{
}
#pragma endregion
#pragma region publicInterface
template<class T>
void IntSet<T>::insert(const T& obj)
{
/*Check if we are initialized*/
if (mySize_ == 0)
{
mySize_ = 1;
myData_ = new T*[mySize_];
}
/*Check if we have place to insert obj in.*/
if (myIndex_ < mySize_)
{//IS IT SAFE TO INCREMENT myIndex while assigning?
myData_[myIndex_++] = &T(obj);//IF I DO IT THE OLD WAY IT WORKS
return;
}
/*We didn't have enough place...*/
T** tmp = new T*[mySize_];//for copying old to temporary basket
std::copy(&myData_[0],&myData_[mySize_],&tmp[0]);
}
#pragma endregion
Thanks.
There's a dedicated C++ casting operator for dealing with const: const_cast
:
myData_[myIndex_++] = &const_cast<T>(obj);
I assume that this is what you're referring to:
myData_[myIndex_++] = &T(obj);//IF I DO IT THE OLD WAY IT WORKS
This is not a cast expression. T(obj)
constructs a temporary object and &
takes the address of it, which is illegal. You can't store a pointer to a temporary because it vanishes when execution gets to the next ;
.
The issue here is not casting but rather how your structure fundamentally stores data. Do you want to make a modifiable copy, owned by the structure? Or do you want to refer to external data which is managed by something else?
If you want the structure to actually contain the data it returns, you could do something like
myData_[myIndex_++] = new T(obj);
(But remember to delete
later.) If you want to reference external data, and yet be able to modify it, you want
void IntSet<T>::insert(T& obj) // remove const
If you want to have non-modifiable references to external data, then
T const ** myData_;
will remove the need to remove const-ness. (But note that this would allow things like insert(3)
to crash the program.)
However
You would be much better off just using C++'s built-in tools. Instead of implementing IntSet
with MakeUnion
, makeIntersection
, and makeSymmetricDifference
, use a sorted std::vector<int>
and/or std::set<int>
with std::set_union
, std::set_intersection
, and std::set_symmetric_difference
.
The problem isn't the cast. If you really intend to store a constant object, then declare your array accordingly, e.g.:
T const ** myData_;
If that's not possible because you actually need to modify the data later, you should then make copy of the argument or reexamine your interface since right now it says you won't be modifying the argument.
Are you sure you want to do this? Why are you storing a pointer to integers passed in instead of the integer itself?
You have a strong possibility of storing a pointer to a temporary; const T& obj
can be created as a temporary from a type that is convertable to T
. For example, if you had the following:
IntSet<int> int_set;
int_set.insert(1);
short foo= 2;
int_set.insert(foo);
Both calls to IntSet<T>::insert
will result in storing a pointer to a temporary value, which is almost always a bug.
What's wrong with the following function?
int * foo() { int x = 3; return &x; }
Where does x exist? When foo returns what happens to x? I think you need to learn the basics before you start going wild with templates and generic programming.
精彩评论