草庐IT

ios - inout 参数的外部实例的 Swift 内存地址与复制的实例相同

coder 2023-09-09 原文

这是我的 Playground 代码。

import Foundation

func printAddress<T>(anyObj: T,message: String = "") {
  var copy = anyObj
  withUnsafePointer(to: &copy) {
    print("\(message) value \(copy) has memory address of: \($0)")
  }
}


class Account {
  var balance: Int = 0
  init(balance: Int) {
    self.balance = balance
  }
}

func deposit(amount: Int, into account: inout Account) {
  account.balance += amount

  printAddress(anyObj: account, message: "After deposit") //0x00007fff569ba188
  printAddress(anyObj: acct,message: "Address of acct within the deposit free function") //0x00007fff59eb6188
  //What makes both memory addresses are same inside the fucntion?
}

func verify(account: Account) -> Bool{
  printAddress(anyObj: acct,message: "Address of acct within the verify function") //0x00007fff5a39a188
  //Again surprisingly same as address used in deposit function copied account var. Optimization?
  return account.balance > 0
}

var acct = Account(balance: 10)
printAddress(anyObj: acct,message:"Before deposit 20") // Print 0x00007fff518751f8

deposit(amount: 20, into: &acct)
verify(account: acct)

printAddress(anyObj: acct,message:"After and deposit and verify completed") //// Print 0x00007fff518751f8

我有 2 个我不清楚的观察结果。

  1. 为什么它为account(复制的实例)和acct(原始acct)打印相同的内存地址
  2. 当我在验证方法调用中打印内存地址时。为什么它再次与先前方法调用中使用的地址相同。是编译器优化的原因吗?

最佳答案

发生的事情是您总是在 printAddress() 函数中打印 copy 变量的地址。您没有打印您传入的参数的地址,即使那是您想要的。

当输入 printAddress() 时,copy 变量的地址始终是超出当前堆栈指针的某个常量固定偏移量,但堆栈指针会根据调用 printAddress() 时代码的嵌套深度。

要查看另一个值,创建一个调用 printAddress() 的函数 foo(),然后从 调用 foo() >验证()

同样,它始终是您在调用 print() 时看到的 copy 变量的内存地址。

如果你想打印传递给 printAddress() 的东西的内存地址,你需要去掉临时的:

func printAddress<T>(anyObj: inout T, message: String = "") {
    withUnsafePointer(to: &anyObj) {
        print("\(message) value \(anyObj) has memory address of: \($0)")
    }
}

现在调用:

printAddress(anyObj: &acct, message: "message")

从任何地方,您都会看到相同的值。

关于ios - inout 参数的外部实例的 Swift 内存地址与复制的实例相同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41918294/

有关ios - inout 参数的外部实例的 Swift 内存地址与复制的实例相同的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  3. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  4. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  5. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  6. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  7. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  8. ruby-on-rails - 在默认方法参数中使用 .reverse_merge 或 .merge - 2

    两者都可以defsetup(options={})options.reverse_merge:size=>25,:velocity=>10end和defsetup(options={}){:size=>25,:velocity=>10}.merge(options)end在方法的参数中分配默认值。问题是:哪个更好?您更愿意使用哪一个?在性能、代码可读性或其他方面有什么不同吗?编辑:我无意中添加了bang(!)...并不是要询问nobang方法与bang方法之间的区别 最佳答案 我倾向于使用reverse_merge方法:option

  9. ruby - 定义方法参数的条件 - 2

    我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano

  10. ruby-on-rails - Rails - 从另一个模型中创建一个模型的实例 - 2

    我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案

随机推荐