tags:

views:

127

answers:

5

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_(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.

+4  A: 

There's a dedicated C++ casting operator for dealing with const: const_cast:

myData_[myIndex_++] = &const_cast<T>(obj);
Michael Mrozek
...you probably want to write that as `` or, even better, directly as `const_cast<T*>(`
vladr
It would be more correct to remove `const` from the argument declaration.
Potatoswatter
Dzięki Michał. Głowę bym sobie dał uciąć, że tak właśnie próbowałem to zrobić parę minut temu i dostawałem błąd compilatora, dlatego też postanowiłem się kogoś spytać co robię nie tak.
There is nothing we can do
@Potatoswatter - could you elaborate on that please?
There is nothing we can do
@Vlad I absolutely love your example.
There is nothing we can do
AndreyT
A: 

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.

MSN
+2  A: 

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.

Potatoswatter
+1 for nice explanaition.
There is nothing we can do
@Potatoswatter I'm still doing my excersises from TC++PL that's why I'm doing everything "by hand". Thanks for advice anyway ;)
There is nothing we can do
Actually, `T(obj)` *is* a cast expression. This is a functional-style cast. In fact, all expressions of the form `TYPE(<arguments>)` are functional-style casts in C++, even if they have zero or more than one argument.
AndreyT
@Andrey: Does the standard refer to it as a cast? I see it described as "Explicit type conversion (functional notation)." Considering that it always constructs an object, "cast" doesn't seem an apt description.
Potatoswatter
I mean, `T x; … T(x) …` will call the copy constructor rather than do nothing. Does copy elision even apply?
Potatoswatter
+1  A: 

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.

Void
A: 
Andrew Rothstein