C++ 使用自引用元素交换容器

C++ 使用自引用元素交换容器,c++,C++,当容器包含具有指向容器本身的指针的元素时,通过指针交换进行交换的标准版本不起作用,交换也不会检查任何这种可能性。 有没有办法告诉容器标准交换不起作用,并使用不同的版本? 实施此类互换的最佳方式是什么 下面的示例解释了该问题 template<template<typename T,typename = std::allocator<T> > class H> struct kid { typedef H<kid> home_type;

当容器包含具有指向容器本身的指针的元素时,通过指针交换进行交换的标准版本不起作用,交换也不会检查任何这种可能性。 有没有办法告诉容器标准交换不起作用,并使用不同的版本? 实施此类互换的最佳方式是什么

下面的示例解释了该问题

template<template<typename T,typename = std::allocator<T> > class H>
struct kid
{
    typedef H<kid> home_type;
    typedef int id_t;
    kid(const home_type& home,int m,typename home_type::size_type c=-1)
        : home_(&home)
        , me_(m)
        , idx_(c)
    {

    }
    id_t me()const
    {
        return me_;
    }
    id_t cousin()const
    {
        return (*home_).size() < idx_ ? -1 : (*home_)[idx_].me();
    }
private://default copy & assign ok???
    const home_type* home_;
    typename home_type::size_type idx_;
    id_t me_;
};

int main()
{
    typedef kid<std::vector> kid_t;
    typedef std::vector<kid_t> home_t;
    home_t home1,home2;//two neighbors
    home1.push_back(kid_t(home1,1));//elderly kid
    home1.push_back(kid_t(home1,2,0));//the cousins
    home1.push_back(kid_t(home1,3,0));
    home1.push_back(kid_t(home1,4,0));

    home2.push_back(kid_t(home2,10));//first kid
    home2.push_back(kid_t(home2,20));//second kid
    home2.push_back(kid_t(home2,30,0));//cousin of first kid.
    home2.push_back(kid_t(home2,40,1));//cousin of second kid

    for(home_t::const_iterator it = home1.begin(); it!= home1.end(); ++it)
    {
        std::cout<<(*it).me()<<" "<<(*it).cousin()<<"\n";
    }
    std::cout<<"\n";
    for(home_t::const_iterator it = home2.begin(); it!= home2.end(); ++it)
    {
        std::cout<<(*it).me()<<" "<<(*it).cousin()<<"\n";
    }
    std::cout<<"\nexchange home\n";
    std::swap(home1,home2);//they exchanged their house, surely this doesn't work. 
    //what is the best way to do this?
    for(home_t::const_iterator it = home1.begin(); it!= home1.end(); ++it)
    {
        std::cout<<(*it).me()<<" "<<(*it).cousin()<<"\n";
    }
    std::cout<<"\n";
    for(home_t::const_iterator it = home2.begin(); it!= home2.end(); ++it)
    {
        std::cout<<(*it).me()<<" "<<(*it).cousin()<<"\n";
    }
    //all the kids got  confused, they points to neighborhood kids as their cousins 
}
模板
结构孩子
{
类型def H home_类型;
typedef int id_t;
kid(常量home_type&home,int m,typename home_type::size_type c=-1)
:主页\主页(&home)
,我(m)
,idx_3;(c)
{
}
id\u t me()常量
{
把钱还给我;
}
id\u t表亲()常量
{
return(*home..size()std::cout您可以为您的类型实现std::swap:

void std::swap(std::vector<kid_t> &first,std::vector<kid_t> &second)
{
  //here is your implementation or three lines of default swap
}
void std::swap(std::vector&first,std::vector&second)
{
//这是您的实现或三行默认交换
}

您可以为您的类型实现std::swap:

void std::swap(std::vector<kid_t> &first,std::vector<kid_t> &second)
{
  //here is your implementation or three lines of default swap
}
void std::swap(std::vector&first,std::vector&second)
{
//这是您的实现或三行默认交换
}

我看不到任何使用
swap
的方法。我能想到的唯一方法是在
kid
中提供一个
move
函数,将孩子从一个家移动到另一个家。然后编写自己的函数来移动孩子。

我看不到任何使用
swap
的方法。我能想到的唯一方法是of在
kid
中提供了一个
move
函数,可以将孩子从一个家移动到另一个家。然后编写自己的函数来移动孩子。

这里的问题似乎更多的是设计问题,而不是交换问题

你(基本上)使用一个指向一个变量的指针,你没有将自己指定为孩子的标识符……因此,当然,只要孩子们四处走动,它就会断开。(实际上,它比指针稍微好一点,但不会太多)

您有两种解决方案:

  • 基本>自己实例化它们
  • 更复杂的>工厂+id
当然,你也有一个问题,那就是你捆绑了
Home
及其实现……但是我让你自己编写一个合适的
Home
类。顺便说一句,由于STL容器的模板参数数量既取决于容器,也取决于你正在使用的STL的实际实现,所以你的解决方案是远没有使用真正的类那么通用;)

基本

class kid
{
public:
  kid(kid* related = 0): m_related(related) {}
  // methods
private:
  // other attributes
  kid* m_related;
};

int main(int argc, char* argv[])
{
  Home home1, home2;
  kid* kid1 = home1.insert(new kid(home1, 1));
  home1.insert(new kid(home1, 2, kid1));

  kid* kid2 = home2.insert(new kid(home2, 1));
  kid* kid3 = home2.insert(new kid(home2, 2));
  home.insert(new kid(home2, 3, kid2));
  home.insert(new kid(home2, 4, kid3));

  swap(home1,home2); // just swapping the vectors, since it only moves pointers not the objects
}
这是最简单的方法,但我当然还是诅咒你,因为我有两个孩子的id是1

工厂

 class KidFactory;

 class KidKey { friend class KidFactory; KidKey() {} };

 class Kid
 {
 public:
   Kid(KidKey, Id id, Id cousinId);

   Id getId() const { return m_id; }

   const Home* getHome() const;
   void setHome(const Home& home);

 private:
   const Home* m_home;
   Id m_id;
   Id m_cousinId;
 };

 // Factory
 class KidFactory
 {
 public:
   Kid& createKid(Id cousinId = -1)
   {
     m_kids.push_back(Kid(KidKey(), m_kids.size(), cousinId));
     return m_kids.back();
   }

   Kid& getKid(Id id)
   {
     return m_kids.at(id); // notice that might generate out_of_range exception
   }

 private:
   std::vector<Kid> m_kids;
 };

 class Home
 {
 public:
   void insert(Kid& kid)
   {
     m_kids.push_back(kid.getId());
     kid.setHome(*this);
   }
 };


 int main(int argc, char* argv[])
 {
   KidFactory factory;
   Home home1, home2;

   home1.insert(factory.createKid());
   home1.insert(factory.createKid(home1.front().getId()));

   Kid& kid1 = factory.createKid();
   home2.insert(kid1);
   home2.insert(factory.createKid(kid1.getId()));

   // once again swapping vectors is fine
 }
class工厂;
类KidKey{friend类KidFactory;KidKey(){};
班童
{
公众:
孩子(孩子,身份证,表亲);
Id getId()常量{return m_Id;}
常量Home*getHome()常量;
无效设置原点(常量原点和原点);
私人:
康斯特之家*m_之家;
Id m_Id;
我是堂兄弟;
};
//工厂
基德级工厂
{
公众:
Kid&createKid(Id cousinId=-1)
{
m_kids.push_back(Kid(KidKey(),m_kids.size(),cousinId));
返回m_kids.back();
}
Kid&getKid(Id)
{
返回m_kids.at(id);//注意,可能会生成超出范围的异常
}
私人:
性病::向量m_儿童;
};
班级之家
{
公众:
无效插入(基德和基德)
{
m_kids.push_back(kid.getId());
kid.setHome(*这个);
}
};
int main(int argc,char*argv[])
{
基德工厂;
Home Home 1、Home Home 2;
home1.insert(factory.createKid());
home1.insert(factory.createKid(home1.front().getId());
Kid&kid1=factory.createKid();
home2.插入(kid1);
home2.insert(factory.createKid(kid1.getId());
//再次交换向量是好的
}

适当的设计导致代码容易编写……但C++中有一些模板:(

< P>)这里的问题似乎比交换问题更像设计问题。 你(基本上)使用一个指向一个变量的指针,你没有将自己指定为孩子的标识符……因此,当然,只要孩子们四处走动,它就会断开。(实际上,它比指针稍微好一点,但不会太多)

您有两种解决方案:

  • 基本>自己实例化它们
  • 更复杂的>工厂+id
当然,你也有一个问题,那就是你捆绑了
Home
及其实现……但是我让你自己编写一个合适的
Home
类。顺便说一句,由于STL容器的模板参数数量既取决于容器,也取决于你正在使用的STL的实际实现,所以你的解决方案是远没有使用真正的类那么通用;)

基本

class kid
{
public:
  kid(kid* related = 0): m_related(related) {}
  // methods
private:
  // other attributes
  kid* m_related;
};

int main(int argc, char* argv[])
{
  Home home1, home2;
  kid* kid1 = home1.insert(new kid(home1, 1));
  home1.insert(new kid(home1, 2, kid1));

  kid* kid2 = home2.insert(new kid(home2, 1));
  kid* kid3 = home2.insert(new kid(home2, 2));
  home.insert(new kid(home2, 3, kid2));
  home.insert(new kid(home2, 4, kid3));

  swap(home1,home2); // just swapping the vectors, since it only moves pointers not the objects
}
这是最简单的方法,但我当然还是诅咒你,因为我有两个孩子的id是1

工厂

 class KidFactory;

 class KidKey { friend class KidFactory; KidKey() {} };

 class Kid
 {
 public:
   Kid(KidKey, Id id, Id cousinId);

   Id getId() const { return m_id; }

   const Home* getHome() const;
   void setHome(const Home& home);

 private:
   const Home* m_home;
   Id m_id;
   Id m_cousinId;
 };

 // Factory
 class KidFactory
 {
 public:
   Kid& createKid(Id cousinId = -1)
   {
     m_kids.push_back(Kid(KidKey(), m_kids.size(), cousinId));
     return m_kids.back();
   }

   Kid& getKid(Id id)
   {
     return m_kids.at(id); // notice that might generate out_of_range exception
   }

 private:
   std::vector<Kid> m_kids;
 };

 class Home
 {
 public:
   void insert(Kid& kid)
   {
     m_kids.push_back(kid.getId());
     kid.setHome(*this);
   }
 };


 int main(int argc, char* argv[])
 {
   KidFactory factory;
   Home home1, home2;

   home1.insert(factory.createKid());
   home1.insert(factory.createKid(home1.front().getId()));

   Kid& kid1 = factory.createKid();
   home2.insert(kid1);
   home2.insert(factory.createKid(kid1.getId()));

   // once again swapping vectors is fine
 }
class工厂;
类KidKey{friend类KidFactory;KidKey(){};
班童
{
公众:
孩子(孩子,身份证,表亲);
Id getId()常量{return m_Id;}
常量Home*getHome()常量;
无效设置原点(常量原点和原点);
私人:
康斯特之家*m_之家;
Id m_Id;
我是堂兄弟;
};
//因素