在c ++中的类中包装算法时,我经常遇到const正确性的问题.我觉得我想要一个可变功能,虽然这是不允许的.任何人都可以建议我如何实现如下的类?
以下是我要编写的代码.
但是,如果用户在不调用run()的情况下请求结果,我希望get_result()函数运行算法.这打破了const的正确性,因为我有一个const函数调用非const函数.
class operate_on_data
{
std::vector<double> m_data; // the data to modify
bool m_completed; // check to see if the function run() has been called
public:
operate_on_data(std::vector<double> data)
: m_data(data), m_completed(false) {} //initialise
void run() //I don't want this function to be const
{
//The algorithm goes here - it alters m_data.
m_completed = true; //the algorithm has been run
}
std::vector<double> get_result() const //I want this function to be const
{
/*The following …Run Code Online (Sandbox Code Playgroud) 我似乎错过了C++中lambda机制的一些观点.这是代码:
std::vector<int> vec (5);
int init = 0;
std::generate(begin(vec), end(vec), [init]() mutable { return ++init; });
for (auto item : vec) {
std::cout << item << " ";
}
std::cout << std::endl << init << std::endl;
Run Code Online (Sandbox Code Playgroud)
如果没有mutable它就不会编译,因为我正在改变initlambda.
现在,我的理解拉姆达被每一个信息载体的一个项目新的全新副本的init是0,所以,1必须每次都返回.但这段代码的输出是:
1 2 3 4 5
0
它看起来像在执行开始时只generate复制init 一次.但为什么?它应该像这样工作吗?
D有两种类型的const:不可变变量是声明为不可变的变量,并且总是不可变的,而const变量只是对象的只读版本.
逻辑const是将函数标记为const,但允许对一个或多个成员变量进行写访问.这种方法的典型用途是进行惰性评估,例如(在C++中)
struct Matrix
{
double determinant() const
{
if ( m_dirty )
{
m_determinant = /* expensive calculation */;
m_dirty = false;
}
return m_determinant;
}
void set(int i, int j, double x) { m_dirty = true; ...; }
mutable bool m_dirty;
mutable double m_determinant;
};
Run Code Online (Sandbox Code Playgroud)
在这里,determinant()是const,但仍然可以修改m_dirty,m_determinant因为它们被标记为mutable.
该d常量(FAQ)说,D2不支持,因为它提供了,这是造成障碍编写并发程序,并使得一定的优化更加困难弱势保证逻辑常量.
我完全理解这个问题,但是如果我们需要逻辑const呢?
考虑上面的情况与Matrix类,但没有缓存(和任何需要逻辑const).还想象一下,这个类在我的代码库中使用,并且主要通过const引用访问.
现在考虑分析已经揭示该determinant()函数是代码中的瓶颈,而且它通常被重复访问,其值很少改变,即如上所述的缓存将是完美的优化.
没有逻辑const我怎么能这样做呢?遍及我的代码库将const引用更改为非const引用不是一种选择(出于显而易见的原因). …
我正在查看API,并且:+方法返回一个新的LinkedList.append方法只允许附加另一个链表.+ =方法需要var才能工作.如果LinkedList是可变的,为什么有人会需要这些?这有什么疯狂的?
如果我在Java中有这样的东西
final LinkedList myList = new LinkedList<String>();
mylist.add("balh");
Run Code Online (Sandbox Code Playgroud)
如何在Scala中实现相同的功能?
在我的函数内部,我通过用数据填充新的可变HashMap来构造结果集(如果有更好的方法 - 我很感激评论).然后我想将结果集作为不可变的HashMap返回.如何从变量中导出一个不可变的?
注意:我正在标记这个Python和C++,因为我已经看到了两者中的例子,但问题是语言无关.
修改对象的函数或类方法有两种选择:直接在相关对象中修改数据,或创建新副本并在保持原始状态不变的情况下返回它.通常,您可以通过查看函数返回的内容来判断哪个是哪个.
有时,您会找到一个尝试同时执行这两项操作的函数,修改原始对象,然后返回该对象的副本或引用.有没有一种情况比只做一个或另一个提供任何优势?
我已经看到了Fluent Interface或Method Chaining的例子,它依赖于返回对象的引用,但这似乎是一个在上下文中应该很明显的特殊情况.
我的第一个坏例子直接来自Python文档,并说明了可变默认参数的问题.对我来说,这个例子是不现实的:如果函数修改了它的参数,那么有一个默认值是没有意义的,如果它返回一个副本,那么应该在进行任何修改之前进行复制.这个问题只存在,因为它试图同时做到这两点.
def f(a, L=[]):
L.append(a)
return L
Run Code Online (Sandbox Code Playgroud)
第二个例子来自CStringT::MakeUpper函数中的Microsoft C++ .文档说明了返回值:
返回字符串的副本,但全部为大写字符.
这导致人们期望原件保持不变.问题的一部分是文档有误导性,如果你看原型,你会发现它正在返回对字符串的引用.除非仔细观察,否则您不会注意到这一点,并将结果分配给新字符串进行编译而没有错误.后来出人意料.
我有一个类模板,看起来像这样:
template<typename T, typename Mutex, typename SomePolicy>
class my_class {
public:
T f() const {
resource_lock a_lock(some_mutex);
return some_policy.some_operation(some_data);
}
private:
T some_data;
mutable Mutex some_mutex;
SomePolicy some_policy;
};
Run Code Online (Sandbox Code Playgroud)
如果不同时使用,我们有一个虚拟互斥类型,它具有所有成员函数作为内联空函数而没有数据.有些策略包含每个实例数据和那些没有任何数据的策略.
这是库代码,事实证明这个类模板在应用程序代码中使用,其中额外的字节对于数据成员是必需的some_mutex,some_policy甚至当它们是空类时.所以我想利用空基优化.对于该政策,这很容易:
template<typename T, typename Mutex, typename SomePolicy>
class my_class {
public:
T f() const {
resource_lock a_lock(the_data.some_mutex);
return the_data.some_operation(the_data.some_data);
}
private:
struct data : SomePolicy {
T some_data;
mutable Mutex some_mutex;
};
data the_data;
};
Run Code Online (Sandbox Code Playgroud)
但是,考虑到这some_mutex一点mutable,我不知道如何使它成为一个没有制作的基类the_data,因此所有数据mutable,从而完全接管编译器的责任,保护我免受愚蠢的常量错误. …
Google提供了大量在F#字典(或其他集合)中添加和删除条目的示例.但我没有看到相当于的例子
myDict["Key"] = MyValue;
Run Code Online (Sandbox Code Playgroud)
我试过了
myDict.["Key"] <- MyValue
Run Code Online (Sandbox Code Playgroud)
我也试图将词典声明为
Dictionary<string, mutable string>
Run Code Online (Sandbox Code Playgroud)
以及这方面的几个变种.然而,我都打不上的正确组合,但...如果它是实际上可能在F#.
编辑:违规代码是:
type Config(?fileName : string) =
let fileName = defaultArg fileName @"C:\path\myConfigs.ini"
static let settings =
dict[ "Setting1", "1";
"Setting2", "2";
"Debug", "0";
"State", "Disarray";]
let settingRegex = new Regex(@"\s*(?<key>([^;#=]*[^;#= ]))\s*=\s*(?<value>([^;#]*[^;# ]))")
do File.ReadAllLines(fileName)
|> Seq.map(fun line -> settingRegex.Match(line))
|> Seq.filter(fun mtch -> mtch.Success)
|> Seq.iter(fun mtch -> settings.[mtch.Groups.Item("key").Value] <- mtch.Groups.Item("value").Value)
Run Code Online (Sandbox Code Playgroud)
我得到的错误是:
System.NotSupportedException: This value may not be mutated
at Microsoft.FSharp.Core.ExtraTopLevelOperators.dict@37-2.set_Item(K key, V value)
at …Run Code Online (Sandbox Code Playgroud) 我希望有这样的不可变Java对象(强烈简化):
class Immutable {
protected String name;
public Immutable(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Run Code Online (Sandbox Code Playgroud)
在某些情况下,对象不仅应该是可读的而且是可变的,因此我可以通过继承添加可变性:
public class Mutable extends Immutable {
public Mutable(String name) {
super(name);
}
public void setName(String name) {
super.name = name;
}
}
Run Code Online (Sandbox Code Playgroud)
虽然这在技术上很好,我想知道它是否符合OOP和继承,mutable也是类型不可变的.我想避免OOP犯罪抛出UnsupportedOperationException不可变对象,就像Java集合API那样.
你怎么看?还有其他想法吗?
我有一个类(A),它有一个struct变量(S).在这个类的一个函数中,我在struct变量上调用一个mutating函数,这个函数需要一个闭包.此闭包的主体检查struct变量的name属性.
结构的变异函数依次调用某个类(B)的函数.这个类的函数再次关闭.在这个闭包的主体中改变结构,即更改name属性,并调用第一个类提供的闭包.
当我们检查struct的name属性时调用第一个类(A)闭包时,它永远不会被更改.
但是在第2步中,如果我使用结构(C)而不是类B,我会看到内部类A的闭包结构实际上已经改变了.以下是代码:
class NetworkingClass {
func fetchDataOverNetwork(completion:()->()) {
// Fetch Data from netwrok and finally call the closure
completion()
}
}
struct NetworkingStruct {
func fetchDataOverNetwork(completion:()->()) {
// Fetch Data from netwrok and finally call the closure
completion()
}
}
struct ViewModelStruct {
/// Initial value
var data: String = "A"
/// Mutate itself in a closure called from a struct
mutating func changeFromStruct(completion:()->()) {
let networkingStruct = NetworkingStruct()
networkingStruct.fetchDataOverNetwork {
self.data = "B"
completion()
}
} …Run Code Online (Sandbox Code Playgroud) mutable ×10
c++ ×4
immutability ×2
scala ×2
const ×1
d ×1
dictionary ×1
f# ×1
inheritance ×1
ios ×1
java ×1
lambda ×1
mvvm ×1
oop ×1
optimization ×1
parameters ×1
python ×1
swift ×1