2010-04-14 3 views
3

J'essaye de chasser const d'un objet mais ça ne marche pas. Mais si j'utilise l'ancienne C-way de compiler le code compile. Alors quel casting je suis supposé utiliser pour obtenir ce même effet? Je ne voudrais pas couler à l'ancienne.Quel casting j'utilise?

//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 

Merci.

Répondre

4

Il y a un dédié C++ opérateur de coulée pour traiter const: const_cast:

myData_[myIndex_++] = &const_cast<T>(obj); 
+2

... vous voulez probablement écrire que '& const_cast (obj)' ou, mieux encore, directement 'const_cast (&obj);' – vladr

+3

Il serait plus correct de supprimer 'const' de la déclaration d'argument. – Potatoswatter

+0

Dzięki Michał glowe bym sobie dal uciąć, że tak właśnie próbowałem à zrobić PARÉ minut temu i dostawałem Błąd compilatora, dlatego też postanowiłem się kogoś spytać co Robie nia tak –

0

Êtes-vous sûr de vouloir le faire? Pourquoi stockez-vous un pointeur sur les entiers passés à la place de l'entier lui-même?

Vous avez une forte possibilité de stocker un pointeur sur un temporaire; const T& obj peut être créé en tant que temporaire à partir d'un type convertible en T. Par exemple, si vous avez les éléments suivants:

IntSet<int> int_set; 
int_set.insert(1); 
short foo= 2; 
int_set.insert(foo); 

Les deux appels à IntSet<T>::insert entraînera le stockage d'un pointeur vers une valeur temporaire, ce qui est presque toujours un bug.

2

Je suppose que c'est ce que vous faites référence:

myData_[myIndex_++] = &T(obj);//IF I DO IT THE OLD WAY IT WORKS 

Ce n'est pas une expression de casting. T(obj) construit un objet temporaire et & prend l'adresse de celui-ci, ce qui est illégal. Vous ne pouvez pas stocker un pointeur sur un temporaire car il disparaît lorsque l'exécution passe à l'étape suivante ;.

Le problème ici n'est pas la distribution, mais plutôt comment votre structure stocke fondamentalement les données. Voulez-vous faire une copie modifiable, appartenant à la structure? Ou voulez-vous vous référer à des données externes qui sont gérées par autre chose?

Si vous voulez que la structure contient effectivement les données qu'il retourne, vous pouvez faire quelque chose comme

myData_[myIndex_++] = new T(obj); 

(Mais souvenez-vous delete plus tard.) Si vous souhaitez référencer des données externes, et pourtant être en mesure de modifier, vous voulez

void IntSet<T>::insert(T& obj) // remove const 

Si vous voulez avoir des références non modifiables à des données externes, puis

T const ** myData_; 

supprimera le besoin de supprimer la constance. (Mais notez que cela permettrait des choses comme insert(3) pour planter le programme.)

Cependant

Vous seriez bien mieux que l'utilisation des outils intégrés de C++. Au lieu de mettre en œuvre IntSet avec MakeUnion, makeIntersection et makeSymmetricDifference, utilisez un tri std::vector<int> et/ou std::set<int> avec std::set_union, std::set_intersection et std::set_symmetric_difference.

+0

+1 pour une belle explication. –

+0

@Potatoswatter Je fais toujours mes excerses de TC++ PL c'est pourquoi je fais tout "à la main". Merci pour les conseils de toute façon;) –

+0

En fait, 'T (obj)' * est * une expression de transtypage. C'est un casting de style fonctionnel. En fait, toutes les expressions de la forme 'TYPE ()' sont des distributions de style fonctionnel en C++, même si elles ont zéro ou plus d'un argument. – AnT

1

Le problème n'est pas la distribution. Si vous avez vraiment l'intention de stocker un objet constant, déclarez votre tableau en conséquence, par ex.:

T const ** myData_; 

Si ce n'est pas possible parce que vous avez réellement besoin de modifier les données plus tard, vous devez alors faire une copie de l'argument ou revoir votre interface car il dit en ce moment, vous ne serez pas en train de modifier l'argument.

-1

Quel est le problème avec la fonction suivante?

int * foo() {int x = 3; return & x; }

Où est-ce que x existe? Quand foo retourne ce qui arrive à x? Je pense que vous devez apprendre les bases avant de commencer à devenir fou avec des modèles et des programmes génériques.