Spring Boot + Security + Thymeleaf和CSRF令牌不会自动注入(Spring Boot + Security + Thymeleaf and CSRF token not injected automatically)
免责声明 :我知道如何使用百万富翁手动注入令牌:
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />`
这篇文章的目标是提高平台的知识,并更好地了解Spring Boot内部的情况
我没有尝试过Spring Boot,但最近我决定尝试一下,并且不得不承认它很棒,但是在Spring MVC上使用Thymeleaf和Security,我不需要在表单上注入CSRF令牌(POST),因为Thymeleaf会自动处理它,但是现在因为某些原因它没有。
从Spring Boot Reference中 ,我找到了application.properties文件中使用的常用属性列表,与thymeleaf和security相关的属性是:
Thymeleaf Properties
spring.thymeleaf.check-template-location=true spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.excluded-view-names= # comma-separated list of view names that should be excluded from resolution spring.thymeleaf.view-names= # comma-separated list of view names that can be resolved spring.thymeleaf.suffix=.html spring.thymeleaf.mode=HTML5 spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.content-type=text/html # ;charset=<encoding> is added spring.thymeleaf.cache=true # set to false for hot refresh
安全属性
security.user.name=user # login username security.user.password= # login password security.user.role=USER # role assigned to the user security.require-ssl=false # advanced settings ... security.enable-csrf=false security.basic.enabled=true security.basic.realm=Spring security.basic.path= # /** security.basic.authorize-mode= # ROLE, AUTHENTICATED, NONE security.filter-order=0 security.headers.xss=false security.headers.cache=false security.headers.frame=false security.headers.content-type=false security.headers.hsts=all # none / domain / all security.sessions=stateless # always / never / if_required / stateless security.ignored= # Comma-separated list of paths to exclude from the default secured paths
但如果让Thymeleaf再次注入令牌的解决方案就在那里,我就看不到了。
编辑 :添加我的配置
该项目是使用最新STS版本(我认为很棒)中提供的初始化程序创建的,其中包括Web,Thymeleaf,Security,JPA,MySQL,H2,Mail,Facebook,Twitter,LinkedIn和Actuator项目,以及添加了一些额外的东西
使用Java 7和Tomcat 7,因为我打算在不久的将来在Openshift上部署项目,接下来有我的配置文件:
的pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.2.3.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <start-class>com.adrisasws.springmvc.WebApplication</start-class> <java.version>1.7</java.version> <tomcat.version>7.0.59</tomcat.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>1.1.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity3</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.social</groupId> <artifactId>spring-social-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-social-facebook</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-social-linkedin</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-social-twitter</artifactId> </dependency> <dependency> <groupId>org.springframework.social</groupId> <artifactId>spring-social-google</artifactId> <version>1.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <profiles> <profile> <id>openshift</id> <build> <finalName>webapp</finalName> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> <configuration> <outputDirectory>webapps</outputDirectory> <warName>ROOT</warName> </configuration> </plugin> </plugins> </build> </profile> </profiles>
安全配置(我在非启动项目中使用的安全文件完全相同,其中CSRF令牌实际上是自动注入的)
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { ////////////////////////////////////////////////////////////////////////// // DEPENDENCIES // ////////////////////////////////////////////////////////////////////////// @Autowired private DataSource dataSource; @Autowired private UserRepository userRepository; ////////////////////////////////////////////////////////////////////////// // PROPERTIES // ////////////////////////////////////////////////////////////////////////// @Value("${custom.security.rememberme-secret}") private String secret; @Value("${custom.security.rememberme-create-tables}") private String createTables; private final static String[] adminRequests = new String[] { ... some matchers here... }; private final static String[] userRequests = new String[] { ... some matchers here... }; private final static String[] publicRequests = new String[] { ...some matchers here... }; ////////////////////////////////////////////////////////////////////////// // AUTHORIZATION // ////////////////////////////////////////////////////////////////////////// @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/css/**", "/images/**", "/js/**", "/error**"); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers(adminRequests).access("hasRole('"+Role.ADMIN.toString()+"')") .antMatchers(userRequests).access("hasRole('"+Role.USER.toString()+"')") .antMatchers(publicRequests).permitAll() .anyRequest().authenticated() .and() .requiresChannel() .anyRequest().requiresSecure() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/", false) .permitAll() .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login?logout") .invalidateHttpSession(true) .deleteCookies("JSESSIONID") .permitAll() .and() .rememberMe() .rememberMeServices(rememberMeService()) .and() .apply(new SpringSocialConfigurer()); } ////////////////////////////////////////////////////////////////////////// // AUTHENTICATION // ////////////////////////////////////////////////////////////////////////// @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(userDetailsService()) .passwordEncoder(bCryptPasswordEncoder()); } @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(11); } @Bean public UserDetailsService userDetailsService() { return new UserRepositoryUserDetailsService(userRepository); } @Bean public SocialUserDetailsService socialUserDetailsService() { return new UserRepositorySocialUserDetailsService(userDetailsService()); } ////////////////////////////////////////////////////////////////////////// // REMEMBER ME // ////////////////////////////////////////////////////////////////////////// @Bean public JdbcTokenRepositoryImpl jdbcTokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); jdbcTokenRepository.setCreateTableOnStartup(Boolean.valueOf(createTables)); return jdbcTokenRepository; } @Bean public RememberMeAuthenticationProvider rememberMeAuthenticationProvider() { return new RememberMeAuthenticationProvider(secret); } @Bean public PersistentTokenBasedRememberMeServices rememberMeService() { PersistentTokenBasedRememberMeServices service = new PersistentTokenBasedRememberMeServices(secret, userDetailsService(), jdbcTokenRepository()); service.setUseSecureCookie(true); service.setParameter("rememberme"); service.setTokenValiditySeconds(AbstractRememberMeServices.TWO_WEEKS_S); return service; } @Bean public RememberMeAuthenticationFilter authenticationFilter() throws Exception { return new RememberMeAuthenticationFilter(authenticationManager(), rememberMeService()); } }
在我的春季靴子配置目前与百里香叶有关,并用于发展目的
spring.thymeleaf.cache=false
和thymeleaf模板看起来像这样(我的登录页面,为了清晰起见,仅包含相关内容)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security/" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="thymeleaf/layouts/default"> <head> ... css and meta tags ... </head> <body> ... some html ... <th:block sec:authorize="isAnonymous()"> <!-- Bad Credentials --> <div th:if="${param.error}" class="alert alert-danger text-center"> Invalid username and/or password. </div> <!-- Logout --> <div th:if="${param.logout}" class="alert alert-success text-center"> You have been logged out. </div> <!-- Login Form --> <form id="f" th:action="@{/login}" method="post" role="form" autocomplete="off"> <!-- Username --> <input type="text" class="form-control text-center" id="username" name="username" th:placeholder="#{form.login.username}" /> <!-- Password --> <input type="password" class="form-control text-center" id="password" name="password" th:placeholder="#{form.login.password}" /> <!-- Remember me --> <input type="checkbox" id="rememberme" name="rememberme" /> <!-- Submit --> <button type="submit" class="btn btn-primary" th:utext="#{form.login.submit}">Login</button> <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" /> </form> ... more html and javascript ... </body> </html>
Edit2 - 在Faraj Farook指向的方向上做了一些调试之后,我发现,在我发布的配置的项目中,在Spring Boot版本中,在这个类
org.thymeleaf.spring4.requestdata.RequestDataValueProcessor4Delegate
,以下函数返回一个空处理器public Map<String, String> getExtraHiddenFields( final RequestContext requestContext, final HttpServletRequest request) { final RequestDataValueProcessor processor = requestContext.getRequestDataValueProcessor(); if (processor == null) { return null; } return processor.getExtraHiddenFields(request); }
而非Spring引导版本,它返回一个处理器,该处理器是
org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor
一个实例。Disclaimer: I know how to inject the token in a form with thymeleaf manually with this:
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />`
The goal of this post is to improve the knowledge of the platform and get a better understanding of what's going on inside Spring Boot
I haven't tried Spring Boot, but recently i just decided to give it a try, and have to admit its awesome, but with Thymeleaf and Security on Spring MVC, i didn't need to inject CSRF token on forms (POST), because Thymeleaf took care of it automatically, but now in Spring Boot for some reason it doesn't.
From the Spring Boot Reference, i found a list of the common properties used on application.properties file, and the ones related to thymeleaf and security are:
Thymeleaf Properties
spring.thymeleaf.check-template-location=true spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.excluded-view-names= # comma-separated list of view names that should be excluded from resolution spring.thymeleaf.view-names= # comma-separated list of view names that can be resolved spring.thymeleaf.suffix=.html spring.thymeleaf.mode=HTML5 spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.content-type=text/html # ;charset=<encoding> is added spring.thymeleaf.cache=true # set to false for hot refresh
Security Properties
security.user.name=user # login username security.user.password= # login password security.user.role=USER # role assigned to the user security.require-ssl=false # advanced settings ... security.enable-csrf=false security.basic.enabled=true security.basic.realm=Spring security.basic.path= # /** security.basic.authorize-mode= # ROLE, AUTHENTICATED, NONE security.filter-order=0 security.headers.xss=false security.headers.cache=false security.headers.frame=false security.headers.content-type=false security.headers.hsts=all # none / domain / all security.sessions=stateless # always / never / if_required / stateless security.ignored= # Comma-separated list of paths to exclude from the default secured paths
But if the solution to make Thymeleaf inject the token again is there, i fail to see it.
Edit: adding my configuration
The project was created using the initializer that was shipped in the last STS version (which in my opinion is awesome), with Web, Thymeleaf, Security, JPA, MySQL, H2, Mail, Facebook, Twitter, LinkedIn and Actuator items checked, and added some extras aftwerwards
Using Java 7 and Tomcat 7 because i intend to deploy the project on Openshift in a near future, and next there are my config files:
pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.2.3.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <start-class>com.adrisasws.springmvc.WebApplication</start-class> <java.version>1.7</java.version> <tomcat.version>7.0.59</tomcat.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>io.spring.platform</groupId> <artifactId>platform-bom</artifactId> <version>1.1.2.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity3</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.social</groupId> <artifactId>spring-social-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-social-facebook</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-social-linkedin</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-social-twitter</artifactId> </dependency> <dependency> <groupId>org.springframework.social</groupId> <artifactId>spring-social-google</artifactId> <version>1.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <profiles> <profile> <id>openshift</id> <build> <finalName>webapp</finalName> <plugins> <plugin> <artifactId>maven-war-plugin</artifactId> <version>2.1.1</version> <configuration> <outputDirectory>webapps</outputDirectory> <warName>ROOT</warName> </configuration> </plugin> </plugins> </build> </profile> </profiles>
Security config (exactly the same security file i'm using in a non-boot project in which the CSRF token actually gets injected automatically)
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { ////////////////////////////////////////////////////////////////////////// // DEPENDENCIES // ////////////////////////////////////////////////////////////////////////// @Autowired private DataSource dataSource; @Autowired private UserRepository userRepository; ////////////////////////////////////////////////////////////////////////// // PROPERTIES // ////////////////////////////////////////////////////////////////////////// @Value("${custom.security.rememberme-secret}") private String secret; @Value("${custom.security.rememberme-create-tables}") private String createTables; private final static String[] adminRequests = new String[] { ... some matchers here... }; private final static String[] userRequests = new String[] { ... some matchers here... }; private final static String[] publicRequests = new String[] { ...some matchers here... }; ////////////////////////////////////////////////////////////////////////// // AUTHORIZATION // ////////////////////////////////////////////////////////////////////////// @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/css/**", "/images/**", "/js/**", "/error**"); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers(adminRequests).access("hasRole('"+Role.ADMIN.toString()+"')") .antMatchers(userRequests).access("hasRole('"+Role.USER.toString()+"')") .antMatchers(publicRequests).permitAll() .anyRequest().authenticated() .and() .requiresChannel() .anyRequest().requiresSecure() .and() .formLogin() .loginPage("/login") .defaultSuccessUrl("/", false) .permitAll() .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login?logout") .invalidateHttpSession(true) .deleteCookies("JSESSIONID") .permitAll() .and() .rememberMe() .rememberMeServices(rememberMeService()) .and() .apply(new SpringSocialConfigurer()); } ////////////////////////////////////////////////////////////////////////// // AUTHENTICATION // ////////////////////////////////////////////////////////////////////////// @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth .userDetailsService(userDetailsService()) .passwordEncoder(bCryptPasswordEncoder()); } @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(11); } @Bean public UserDetailsService userDetailsService() { return new UserRepositoryUserDetailsService(userRepository); } @Bean public SocialUserDetailsService socialUserDetailsService() { return new UserRepositorySocialUserDetailsService(userDetailsService()); } ////////////////////////////////////////////////////////////////////////// // REMEMBER ME // ////////////////////////////////////////////////////////////////////////// @Bean public JdbcTokenRepositoryImpl jdbcTokenRepository() { JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); jdbcTokenRepository.setDataSource(dataSource); jdbcTokenRepository.setCreateTableOnStartup(Boolean.valueOf(createTables)); return jdbcTokenRepository; } @Bean public RememberMeAuthenticationProvider rememberMeAuthenticationProvider() { return new RememberMeAuthenticationProvider(secret); } @Bean public PersistentTokenBasedRememberMeServices rememberMeService() { PersistentTokenBasedRememberMeServices service = new PersistentTokenBasedRememberMeServices(secret, userDetailsService(), jdbcTokenRepository()); service.setUseSecureCookie(true); service.setParameter("rememberme"); service.setTokenValiditySeconds(AbstractRememberMeServices.TWO_WEEKS_S); return service; } @Bean public RememberMeAuthenticationFilter authenticationFilter() throws Exception { return new RememberMeAuthenticationFilter(authenticationManager(), rememberMeService()); } }
in my spring boot configt at the moment related to thymeleaf, and for development purposes
spring.thymeleaf.cache=false
and thymeleaf templates look like this (my login page at the moment, will include only the relevant content for the sake of clarity)
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security/" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorator="thymeleaf/layouts/default"> <head> ... css and meta tags ... </head> <body> ... some html ... <th:block sec:authorize="isAnonymous()"> <!-- Bad Credentials --> <div th:if="${param.error}" class="alert alert-danger text-center"> Invalid username and/or password. </div> <!-- Logout --> <div th:if="${param.logout}" class="alert alert-success text-center"> You have been logged out. </div> <!-- Login Form --> <form id="f" th:action="@{/login}" method="post" role="form" autocomplete="off"> <!-- Username --> <input type="text" class="form-control text-center" id="username" name="username" th:placeholder="#{form.login.username}" /> <!-- Password --> <input type="password" class="form-control text-center" id="password" name="password" th:placeholder="#{form.login.password}" /> <!-- Remember me --> <input type="checkbox" id="rememberme" name="rememberme" /> <!-- Submit --> <button type="submit" class="btn btn-primary" th:utext="#{form.login.submit}">Login</button> <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" /> </form> ... more html and javascript ... </body> </html>
Edit2 - after doing some debugging in the direction Faraj Farook pointed, i found out that, in a project with the configuration i posted, in the Spring Boot version, in this class
org.thymeleaf.spring4.requestdata.RequestDataValueProcessor4Delegate
, the following function returns a null processorpublic Map<String, String> getExtraHiddenFields( final RequestContext requestContext, final HttpServletRequest request) { final RequestDataValueProcessor processor = requestContext.getRequestDataValueProcessor(); if (processor == null) { return null; } return processor.getExtraHiddenFields(request); }
whereas the non Spring boot version, it returns a processor which is an instance of
org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor
.
原文:https://stackoverflow.com/questions/29509392
最满意答案
如果您不想更改项目以及希望避免复制,则
auto const &
是正确的选择:for (auto const &x : vec)
谁建议你使用
auto &
错误。 别理他们。这里是回顾:
- 当您要使用副本时选择
auto x
。- 选择
auto &x
当您想要处理原始项目,并可能会修改它们。- 当您想使用原始项目时选择
auto const &x
,不会修改它们。If you don't want to change the items as well as want to avoid making copies, then
auto const &
is the correct choice:for (auto const &x : vec)
Whoever suggests you to use
auto &
is wrong. Ignore them.Here is recap:
- Choose
auto x
when you want to work with copies.- Choose
auto &x
when you want to work with original items and may modify them.- Choose
auto const &x
when you want to work with original items and will not modify them.
相关问答
更多-
迭代基本类型时使用const引用的任何缺点?(Any disadvantage of using const reference when iterating over basic types?)[2022-07-19]
标准容器都是从它们的迭代器中返回引用(但是,请注意,有些“容器不是真正的容器,例如, std::vector它返回一个代理)。其他迭代器可能会返回代理或值,尽管这不是'严格支持。 当然,这个标准对性能没有任何保证。 任何类型的性能相关特性(超出复杂性保证范围)都被认为是实现的质量。 也就是说,你可能想要考虑让编译器像以前一样为你做出选择: for (auto&& e: coll) { f(e); } 这里的主要问题是f()可能会收到非const引用。 如果需要,可以使用const一个const ... -
template
std::remove_reference_t const& as_const(T&&t){return t;} 可能有帮助。 返回右值的隐式共享对象可以隐式检测由于非常量迭代而导致的写入划分(和划分)。 这给你: for(auto&&item : as_const(foo())) { } 它可以让你以const方式迭代(并且很清楚)。 如果您需要参考寿命延长才能正常工作,请重复2次: template T const as_const(T&& ... -
C ++ 11基于范围的循环:通过值获取项或引用const(C++11 range based loop: get item by value or reference to const)[2023-06-02]
如果您不想更改项目以及希望避免复制,则auto const &是正确的选择: for (auto const &x : vec) 谁建议你使用auto &错误。 别理他们。 这里是回顾: 当您要使用副本时选择auto x 。 选择auto &x当您想要处理原始项目,并可能会修改它们。 当您想使用原始项目时选择auto const &x ,不会修改它们。 If you don't want to change the items as well as want to avoid making copies, ... -
可能有办法,但我非常怀疑它会更加优雅。 你在第一个循环中已经是正确的方法,限制了循环变量的范围/生命周期。 我会简单地忽略未使用的变量警告(毕竟,这只是编译器的一个迹象, 可能是错误的),或者使用编译器工具(如果有的话)可以在这一点上关闭警告。 There may be a way to do it but I very much doubt it would be more elegant. What you have in that first loop is already the correct w ...
-
是。 同样的原因,如果你只读过一个参数,你使参数const& 。 T // I'm copying this T& // I'm modifying this const T& // I'm reading this 那些是你的“默认值”。 当T是一个基本类型(内置)时,通常只要恢复为const T (无参考)才能读取,因为副本比别名便宜。 我正在开发一个正在开发的程序,因为效率是至关重要的 不要盲目地改变。 一个工作程序比一个快速但破碎的程序更好。 你如何迭代循环可能不会有太大 ...
-
使用基于范围的for循环来替换C ++ 11中的传统嵌套循环(Using range based for loop to replace traditional nested loops in C++11)[2022-08-07]
您的情况实际上是不能使用基于范围的迭代的典型情况。 只要您不关心容器中元素/迭代器的位置,就可以使用它。 相反,如果需要当前元素的索引(或指向它的迭代器),则需要经典循环。* 看你的例子: for(const auto& itr_m : myClassVec) 这里, itr_m不是迭代器,而是对MyClass const*的引用,这意味着您丢失了有关元素位置的所有信息。 *你当然可以在一个range-for循环中跟踪当前元素,但这会破坏它的目的并使代码更难阅读。 Your case actually i ... -
如果您实际想要执行的操作是您在示例中编写的简单操作,则实现您想要的操作的更好方法是: std::cout << std::string{boost::distance(input), '.'}; 否则,如果你只是想遍历一个范围并为每个元素执行一个操作,忽略元素值,那么for_each
就是你想要的。 使用boost: #include boost::for_each(input, [](auto&& /*ignored*/) { ... -
N4606(C ++ 17 draft)3.3.3 basic.scope.block,第4节说 在init-statement,for-range-declaration以及if,while,for和switch语句的条件中声明的名称是if,while,for或switch语句(包括受控语句)的本地名称,以及不得在该陈述的后续条件下,也不得在受控陈述的最外层(或对于if陈述,任何最外面的区块)重新宣布; 见6.4 缩短: 在... for-range-declaration ...中声明的名称是... f ...
-
问题是QJsonArray的迭代器返回一个临时的QJsonValueRef对象,而左值引用无法绑定到临时对象。 我们可以按价值暂时保留: // QJsonArray oldArray contains an array of which one element is "bar" QJsonArray newArray; for (auto v : oldArray) { QJsonObject element = v.toObject(); element["foo"] = element[ ...
-
从你的语法看来, ticket是一个(聪明的)指针。 ticket->ClearCalled(); 这意味着ticket的类型可能类似于 const std::shared_ptr< Ticket >& ticket 你需要的是 const std::shared_ptr< const Ticket >& ticket; // ^^^^^ From your syntax it seems that ticket is a (smart?) pointer. t ...