请考虑以下代码:
std::string my_error_string = "Some error message";
// ...
throw std::runtime_error(std::string("Error: ") + my_error_string);
Run Code Online (Sandbox Code Playgroud)
传递给runtime_error的字符串是字符串返回的临时字符串operator+.假设此异常的处理方式如下:
catch (const std::runtime_error& e)
{
std::cout << e.what() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
字符串的临时返回何时被operator+销毁?语言规范有什么可说的吗?另外,假设runtime_error接受了一个const char*参数,并抛出如下:
// Suppose runtime_error has the constructor runtime_error(const char* message)
throw std::runtime_error((std::string("Error: ") + my_error_string).c_str());
Run Code Online (Sandbox Code Playgroud)
现在什么时候运算符+返回的临时字符串被销毁?它会在catch块尝试打印之前被销毁,这就是为什么runtime_error接受std :: string而不是const char*?
以下部分演示了我的问题:( GCC上的编译错误)
stringstream ss;
string s;
ss << "Hello";
// This fails:
// s.swap(ss.str());
// This works:
ss.str().swap(s);
Run Code Online (Sandbox Code Playgroud)
我的错误:
constSwap.cc:14: error: no matching function for call to 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >::swap(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
basic_string.tcc:496: note: candidates are: void std::basic_string<_CharT, _Traits, _Alloc>::swap(std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>]
Run Code Online (Sandbox Code Playgroud)
虽然我理解stringstream中的str()返回一个临时的,但它没有意义,并且我不应该立即明白我应该使用局部变量作为参数而不是我的第一直觉调用临时交换.
显然,直接赋值工作得更好,而较新的C++标准已经移动了完美的语义,但这些并不适用于我的实现.
Visual Studio因为放松了C++标准而没有出现这个问题.我有点已经理解了对临时事物的整个const引用(我假设是我编译错误的原因).
我的问题:任何人都可以向我解释这是否是唯一的解决方案,并且可能会向我解释将来如何考虑这个问题,以便我可以发现并解决类似的问题?
(如果没有人有任何有用的见解,我至少会在这里为有类似问题的人发帖)
让我们来看看这两个功能:
std::string get_string()
{
std::string ret_value;
// Calculate ret_value ...
return ret_value;
}
void process_c_string(const char* s)
{
std::cout << s << endl;
}
Run Code Online (Sandbox Code Playgroud)
这里有两个可能的process_c_string带有参数的调用get_string.
没有绑定const引用的返回对象get_string.
process_c_string(get_string().c_str());
Run Code Online (Sandbox Code Playgroud)用绑定const引用返回的对象get_string.
const std::string& tmp_str = get_string();
process_c_string(tmp_str.c_str());
Run Code Online (Sandbox Code Playgroud)我知道第二种方式是有效的,但第一种方式是什么,标准对此案例有什么看法呢?返回的临时对象是否get_string会在process_c_str完成之前删除,因为没有const reference它?
注意:这两个版本在MSVC中都可以.
考虑以下代码处理const引用:
const int & func (const int &x)
{
return x;
}
struct Foo {
Foo (const int &x)
: m_x(x) {}
const int & getX ()
{ return m_x; }
const int &m_x;
};
Run Code Online (Sandbox Code Playgroud)
我想知道现在允许以下哪些内容(如果有的话):
int x = func(int(7));
int y = Foo(int(7)).getX();
Run Code Online (Sandbox Code Playgroud)
是否保证临时int对象在赋值使用之前仍然存在或getX?
更新:所以看起来这是安全的 - 但为什么呢?
考虑存储指针而不是引用的边缘情况:
struct Foo {
Foo (const int &x)
: m_x(&x) {}
const int & getX ()
{ return *m_x; }
const int *m_x;
};
int …Run Code Online (Sandbox Code Playgroud) 当试图在临时表中插入6000行时,我收到以下消息
INSERT语句中的行值表达式数超过了允许的最大1000行值.
来源不在SQL Server.
CREATE TABLE #TMP_ISIN (
[Isin] nVARCHAR(250))
INSERT INTO #TMP_ISIN ([Isin])
VALUES
ABOUT 6000 ROWS
Run Code Online (Sandbox Code Playgroud)
我该如何避免这个限制?
C++标准草案N4296说
[class.temporary/5]第二个上下文是引用绑定到临时的.引用绑定的临时值或作为绑定引用的子对象的完整对象的临时值在引用的生命周期内持续存在,除了...
所以我想知道如果两个或多个引用绑定到临时引发会发生什么.它在标准中是否具体?以下代码可能是一个示例:
#include <iostream> //std::cout
#include <string> //std::string
const std::string &f() {
const std::string &s = "hello";
static const std::string &ss = s;
return ss;
}
int main() {
const std::string &rcs = f();
std::cout << rcs; //empty output
//the lifetime of the temporary is the same as that of s
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果我们改变边界顺序,情况就不同了.
#include <iostream> //std::cout
#include <string> //std::string
const std::string &f() {
static const std::string &ss = "hello";
const std::string &s = ss;
return …Run Code Online (Sandbox Code Playgroud) 在GCC 5.4.0中stl_algobase.h我们有:
template<typename _ForwardIterator, typename _Tp>
inline typename
__gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type
__fill_a(_ForwardIterator __first, _ForwardIterator __last,
const _Tp& __value)
{
for (; __first != __last; ++__first)
*__first = __value;
}
template<typename _ForwardIterator, typename _Tp>
inline typename
__gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type
__fill_a(_ForwardIterator __first, _ForwardIterator __last,
const _Tp& __value)
{
const _Tp __tmp = __value;
for (; __first != __last; ++__first)
*__first = __tmp;
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么标量的变体比一般变体有任何优势.我的意思是,它们不会被编译成完全相同的东西吗?__value从堆栈加载到寄存器中并在整个循环中使用该寄存器?
早上好:情况如下
.h文件
extern const std::string void_string_;
extern const int zero_int;
template <typename Class>
inline const Class& zero()
{
// an error message
}
template <>
inline const int& zero<int>()
{
return zero_int;
}
template <>
inline const std::string& zero<std::string>()
{
return void_string_;
}
Run Code Online (Sandbox Code Playgroud)
.cpp文件
const std::string void_string_="";
const int zero_int=0;
Run Code Online (Sandbox Code Playgroud)
然后我用这两个函数调用
zero<int>()
zero<string>()
Run Code Online (Sandbox Code Playgroud)
现在,编译器给我一个警告
zero<int>()
Warning: returning reference to temporary
Run Code Online (Sandbox Code Playgroud)
好吧,我知道,理论上,为什么我会收到警告:当我使用临时引用时.没关系.仍然我不明白为什么const int zero_int; 被认为是暂时的.
谢谢你的任何澄清.
编辑:根据评论的建议,我编辑了Class&zero模板.虽然最初我不能包含错误代码(因为错误消息是一个函数),我清理它以在此处发布并有效地在过程中我理解错误的原因.特别:
template <typename Class>
inline const Class& zero()
{
std::cout << …Run Code Online (Sandbox Code Playgroud) GCC 7.2和Clang 5.0在这种情况下不一致:
struct A;
A foo();
struct A
{
static void bar()
{
foo();
}
private:
~A()=default;
};
A foo()
{
return {};
//GCC error: A::~A() is private in this context.
};
Run Code Online (Sandbox Code Playgroud)
此行为是"c ++ 17保证(复制省略并且与RVO或NRVO无关)"的一部分.
GCC不会编译此代码,但Clang会这样做.哪一个错了?
也许这段话说机器人Clang和GCC符合标准[class.temporary]:
当类类型X的对象传递给函数或从函数返回时,如果X的每个复制构造函数,移动构造函数和析构函数都是微不足道的或删除的,并且X至少有一个未删除的复制或移动构造函数,则实现是允许创建一个临时对象来保存函数参数或结果对象.临时对象分别由函数参数或返回值构造,并且函数的参数或返回对象被初始化,就好像通过使用未删除的普通构造函数来复制临时对象(即使该构造函数不可访问或不会被选中)通过重载决策来执行对象的复制或移动).[注意:允许此纬度允许类类型的对象传递给寄存器中的函数或从寄存器中的函数返回. - 结束说明]
考虑来自7.6.1.10第3段[expr.const.cast](N4810)的示例:
typedef int *A[3]; // array of 3 pointer to int
typedef const int *const CA[3]; // array of 3 const pointer to const int
...
A &&r2 = const_cast<A&&>(CA{}); // OK
Run Code Online (Sandbox Code Playgroud)
因此,该标准说这是合法代码,但是
没有一个g++-7或clang-6编译正常。
事实上,这种const_cast产权相关评论从llvm状态:
....
if (isa<RValueReferenceType>(DestTypeTmp) && SrcExpr.get()->isRValue()) {
if (!SrcType->isRecordType()) {
// Cannot const_cast non-class prvalue to rvalue reference type. But if
// this is C-style, static_cast can do this.
msg …Run Code Online (Sandbox Code Playgroud)