我有一个看起来像这样的课程:
class S
{
public:
int* data;
S() : data(new int[10]) {}
};
构造函数分配10个整数的内存,默认的复制构造函数只是复制指针本身而不是内容。
即使S
的实例具有const
修饰符,我也可以修改data
指向的数据,因为该数据本身没有const
修改。我可以通过将data
设为私有来避免这种情况,并且只允许通过非const
方法进行写访问:
class S
{
private:
int* data;
public:
S() : data(new int[10]) {}
int& operator(size_t i)
{
return data[i];
}
const int& operator(size_t i) const
{
return data[i];
}
};
但现在我可以使用复制构造函数来绕过const
实例的S
,如下所示:
void main()
{
const S a; // Allocates memory
S b(a); // Also points to memory allocated for a
b(1) = 3; // Writes to a even though it is not supposed to be mutable
}
解决此问题的优雅方法是什么(可能使用模板)?
const S
实例指向的数据在使用此实例时根本不应该是可变的。const S
和S
都应该通过复制构造函数创建,给定S
的实例,使const
实例无法修改数据,但非 - const
实例可以。答案 0 :(得分:1)
通过提供两个不同的复制构造函数,可以在复制构造函数中知道正在复制的对象是否为{1: ['1', 'http://www.tennisabstract.com/cgi-bin/wplayer.cgi?p=VictoriaAzarenka', 'Victoria Azarenka', 'BLR', '1989-07-31'], 2: ['1146', 'Brittany Lashway', 'USA', '1994-04-06']}
,一个参数采用const
参数而另一个参数不采用const
。编译器将选择与传递的参数匹配的版本。在构造函数中设置一个标志,以便在执行非const操作时抛出错误。
避免问题中显示的泄漏内存的最佳方法是使用类似std::shared_ptr
的智能指针而不是原始指针。不幸的是shared_ptr
适用于单个对象,而不是数组;可行的解决方法as in this StackOverflow question。我现在不打算尝试解决这个问题,下面的代码仍有漏洞。
要完成,您应该遵循Rule of Three并提供operator=
和析构函数。我将此作为练习留给读者。
class S
{
private:
int* data;
bool is_const;
public:
S() : data(new int[10]), is_const(false) { data[1] = 42; }
S(const S& other) : data(other.data), is_const(true) {}
S(S& other) : data(other.data), is_const(false) {}
int& operator()(size_t i)
{
if (is_const)
throw std::logic_error("non-const operation attempted");
return data.ptr[i];
}
const int& operator()(size_t i) const
{
return data.ptr[i];
}
};
查看实际操作:http://ideone.com/SFN89M
答案 1 :(得分:0)
删除S
的复制构造函数(和赋值运算符)。创建一个新的代理类(SCopy
),其中包含指向S
对象的指针(传递给SCopy
的构造函数)。然后SCopy
将实现const int &operator() const
而不是非const版本。
这样就可以在S
中实现一个析构函数,它可以释放你当前正在泄漏的内存。