#include<iostream>
#include<set>
template <typename T>
/* Simple smart pointer class */
class SmartPtr
{
T *ptr;
public:
explicit SmartPtr(T *p = NULL) { ptr = p; }
~SmartPtr() { delete(ptr); }
T & operator * () { return *ptr; }
T * operator -> () { return ptr; }
};
class simple {
private:
int x;
public:
simple(int y = 0) :x(y) {}
int getX() { return x; }
};
typedef SmartPtr<simple> simplePtr;
int main() {
std::set<simplePtr> st;
simplePtr p1 = simplePtr(new simple(5));
simplePtr p2 = simplePtr(new simple(5));
simplePtr p3 = simplePtr(new simple(5));
simplePtr p4 = simplePtr(new simple(5));
std::cout << p1->getX(); <-- working fine
st.insert(p1);
st.insert(p2);
st.insert(p3);
st.insert(p4);
for (std::set<simplePtr>::iterator it = st.begin(); it != st.end(); ++it)
{
std::cout << it->getX(); // Not working??
}
}
编译失败,并在Visual Studio 2013中出错:
Error C2039 getX: is not a member of SmartPtr<simple>
在linux上:
error: ‘const class SmartPtr<simple>’ has no member named ‘getX’
这是迭代器的问题吗?
答案 0 :(得分:4)
您可以将it->getX()
视为(*it).getX()
的语法糖。 [原则上,类可以不一致地重载->
和*
(解除引用)运算符,但不出所料,std::set<T>::iterator
不会破坏该约定。因此,在您的情况下,*it
被解除引用为const SmartPtr<simple>&
类型的左值,并且应用于它的.getX()
失败,因为SmartPtr
没有getX()
}} 方法。因为,相反,您要访问获取的SmartPtr
指向的对象,您必须再添加一个解除引用级别:
更正1
将
it->getX()
替换为(**it).getX()
或(*it)->getX()
。
还有另一个问题 - *it
会产生 const
SmartPtr
(是的,std::set
的非常量迭代器不提供对容器元素的写访问权限,否则您可能会破坏容器中元素的正确排序)。但->
中的*
和SmartPtr
(解除引用)运算符都是以这样的方式定义的,即只能在非const
对象上调用它们。要解决这个问题,您必须使这两个函数const
:
更正2(在
SmartPtr<T>
)// vvvvv T & operator * () const { return *ptr; } T * operator -> () const { return ptr; } // ^^^^^
进行第二次校正后,您可以使用range-for循环替换旧式for循环:
for (const simplePtr& p : st)
{
std::cout << p->getX();
}
但是,您的程序仍然无法编译 - SmartPtr<T>
对象无法放入std::set
,因为它们不是可比较的。通过定义operator<()
:
更正3
添加到
SmartPtr<T>
:bool operator<(const SmartPtr& other) const { return ptr < other.ptr; }
此时您的代码将编译,但很可能无法正常工作。原因是SmartPtr<T>
的复制语义留给编译器自行决定,这无法满足您的意图。通过发现Rule of Three, Four and Five的违规行为很容易猜到 - 您的类定义了析构函数但未能定义副本和/或移动构造函数和赋值运算符。因此,您的代码执行双重删除,因此无法保证任何定义良好的行为。
更正4
修复
的复制语义SmartPtr<T>
。
我通过将移动语义分配给SmartPtr
来“修复”您的代码(这需要在std::move()
将insert()
添加到std::set
时添加#include<iostream>
#include<set>
template <typename T>
class SmartPtr
{
T *ptr;
public:
explicit SmartPtr(T *p = NULL) { ptr = p; }
~SmartPtr() { delete(ptr); }
SmartPtr(const SmartPtr& other) = delete;
SmartPtr(SmartPtr&& other) : ptr(other.ptr) { other.ptr = NULL; }
SmartPtr& operator=(SmartPtr other)
{
std::swap(ptr, other.ptr);
return *this;
}
T & operator * () const { return *ptr; }
T * operator -> () const { return ptr; }
bool operator<(const SmartPtr& other) const { return ptr < other.ptr; }
};
class simple {
int x;
public:
simple(int y = 0) : x(y) {}
int getX() { return x; }
};
typedef SmartPtr<simple> simplePtr;
int main() {
std::set<simplePtr> st;
simplePtr p1 = simplePtr(new simple(5));
simplePtr p2 = simplePtr(new simple(5));
st.insert(std::move(p1));
st.insert(std::move(p2));
for (const simplePtr& p : st)
{
std::cout << p->getX();
}
return 0;
}
:
body
答案 1 :(得分:2)
你的迭代器需要被解引用,此时你会得到一个指针。然后需要解除引用。所以:
std::cout << (*it)->getX();
答案 2 :(得分:0)
对于初学者,您必须先为班级operator <
定义SmartPtr
,然后才能在集合中使用它。
其次,您必须声明成员函数getX
,如
int getX() const { return x; }
你必须写至少像
std::cout << ( *it )->getX();