在 C 或 C 中,修改 for 循环内的循环变量是令人讨厌的错误的来源:
int main() {
std::vector<int> v (30);
std::iota(v.begin(), v.end(), 0);
int j = 0;
for (size_t i = 0; i < v.size(); i++) {
std::cout << v[i] << ' ' << i << '\
';
i++; // oops, I mean j++
}
std::cout << j << '\
';
}有什么方法可以禁止或警告在编译器或其他东西的帮助下修改循环体内的循环变量?如果可能的话,我该怎么做?
如果你使用 C 的 ranged-for,你可以使循环变量
for (const size_t i : boost::irange<size_t>(0, v.size()))
{
std::cout << v[i] << ' ' << i << '\
';
// i++; // error, can't modify const
}对于 C,你可以创建一个索引类来使用。因此,以下内容将是一个起点。我确信它可以改进,因为我没有考虑太多。
class CIndex {
private:
size_t m_index;
public:
CIndex(size_t i=0) : m_index(i) {}
~CIndex() {};
size_t inc(void) { return ++m_index; }
size_t val(void) { return m_index; }
bool operator < (size_t i) { return m_index < i; }
CIndex & operator =(size_t i) = delete;
};并且它会被用作:
for (CIndex x; x < 10; x.inc()) {
std::cout << argv[x.val()];
x = 3; // generates an error with Visual Studio 2017
}您可以使用转换运算符修改上述类,使其更直观并类似于标准
修改后的类看起来像:
class CIndex {
private:
size_t m_index;
public:
CIndex(size_t i = 0) : m_index(i) {}
~CIndex() {};
size_t inc(size_t i = 1) { return (m_index += i); } // increment operator
size_t dec(size_t i = 1) { return (m_index -= i); } // decrement operator
CIndex & operator =(size_t i) = delete;
operator size_t() const { return m_index; }
};这将允许您在几乎可以使用
但是对于 C 语言规范,这并没有允许您将变量标记为在特定范围内不可变或不变。
您真正要求的是能够标记特定的代码行以允许更改变量并标记不允许更改变量的其他代码行。 C 语言规范没有该功能。
在 C 中,你可以隐藏名称并重新声明另一个与
for (int i = 0; i < 10; ++i)
{
const int t = i, i = t;
printf("i = %d.\
", i); // Works.
i = 4; // Yields compiler error.
}我不建议这样做,但您可以通过以下方式使其不那么难看:
#define Protect(Type, Original) \\
const Type Auxiliary_##Original = Original, Original = Auxiliary_##Original然后使用:
for (int i = 0; i < 10; ++i)
{
Protect(int, i);
printf("i = %d.\
", i); // Works.
i = 4; // Yields compiler error.
}编辑:回答您的最新评论:
Yes, what I'm looking for was just if there is a compiler option that warns it. If there isn't, maybe I should just code more carefully.
不,不幸的是,在 C 中没有。是的,您应该更仔细地编码。一般来说,我建议您考虑一下为什么要拥有这样的功能。如果循环内的"保护"索引变量是一个问题,我会首先问自己我的编码风格是否有意义并且是一致的。
正如 Eric Postpischil 所注意到的,您可以使用一个临时变量将您的索引变量隐藏在一个内部块中作为
然而,这会产生阴影警告(特别是
shadow.c:9:14: warning: declaration of ‘i’ shadows a previous local [-Wshadow]
const int i = t;
^
shadow.c:4:11: note: shadowed declaration is here
for (int i = 0; i < 10; ++i)为避免这种情况,您可以使用简单的诊断
for (int i = 0; i < 10; ++i)
{
const int t = i;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored"-Wshadow"
{
const int i = t;
printf("i = %d\
", i);
i = 4; // Will yield a compiler error.
}
#pragma GCC diagnostic pop
}上面的代码有效(当然删除了
注意:这肯定不是好的做法,但 AFAICT 它是在 C 中实现这种行为的唯一方法。
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是