多年前我相信C与C++相比绝对纯净,因为编译器无法生成任何你无法预测的代码.我现在相信反例包括volatile关键字和内存障碍(在多处理器编程或内存映射硬件设备的设备驱动程序中,其中普通汇编语言甚至比C编译器的优化更纯粹).
目前我正在尝试枚举C++编译器可以执行的不可预测的事情.关于C++的主要抱怨是编译器将隐式实例化临时对象,但我相信这些情况都可以预期.我正在考虑的案例是:
explicit关键字operator ()还有其他人吗?
看看这段代码片段
struct S{ int i; int j;};
int main()
{
assert(S().i == S().j) // is it guaranteed ?
}
Run Code Online (Sandbox Code Playgroud)
为什么?
请考虑以下代码:
#include <sstream>
#include <iostream>
class Foo : public std::stringstream {
public:
~Foo() { std::cout << str(); }
};
int main()
{
Foo foo;
foo << "Test1" << std::endl;
Foo() << "Test2" << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我执行此操作时,它给了我:
004177FC
Test1
Run Code Online (Sandbox Code Playgroud)
我不明白为什么第二个例子给我带来胡言乱语.临时应该存在直到整个表达式被评估,那么为什么它与第一个例子的行为不一样?
请考虑以下代码:
class A {
A(const A&);
public:
A() {}
};
int main() {
const A &a = A();
}
Run Code Online (Sandbox Code Playgroud)
此代码与GCC 4.7.2编译良好,但无法使用Visual C++ 2010进行编译,并出现以下错误:
test.cc(8) : error C2248: 'A::A' : cannot access private member declared in class 'A'
test.cc(2) : see declaration of 'A::A'
test.cc(1) : see declaration of 'A'
Run Code Online (Sandbox Code Playgroud)
因此,在将临时绑定到引用时,是否有必要使用复制构造函数?
这与我之前的问题有些相关:
我正在创建一个包含以下部分的记录器:
// #define LOG(x) // for release mode
#define LOG(x) log(x)
log(const string& str);
log(const ostream& str);
Run Code Online (Sandbox Code Playgroud)
有了这样的想法:
LOG("Test");
LOG(string("Testing") + " 123");
stringstream s;
LOG(s << "Testing" << 1 << "two" << 3);
Run Code Online (Sandbox Code Playgroud)
这一切都按预期工作,但当我这样做时:
LOG(stringstream() << "Testing" << 1 << "two" << 3);
Run Code Online (Sandbox Code Playgroud)
这是行不通的:
void log(const ostream& os)
{
std::streambuf* buf = os.rdbuf();
if( buf && typeid(*buf) == typeid(std::stringbuf) )
{
const std::string& format = dynamic_cast<std::stringbuf&>(*buf).str();
cout << format << endl;
}
}
Run Code Online (Sandbox Code Playgroud)
导致'format'包含垃圾数据而不是通常正确的字符串.
我认为这是因为<<运算符返回的临时ostream比它来自的字符串流更长.
还是我错了?
(为什么string()以这种方式工作?是因为它返回对它自己的引用吗?我假设是的.)
我真的很想这样做,因为我在登录发布模式时会省去额外的分配.
任何以这种方式完成任务的指针或技巧都会受到欢迎.在我的实际解决方案中,我有许多不同的日志功能,它们都比这更复杂.所以我更希望在调用代码中以某种方式实现它.(如果可能的话,不要修改我的#define) …
我试过以下代码:
#include<iostream>
#include<string>
using namespace std;
string f1(string s)
{
return s="f1 called";
}
void f2(string *s)
{
cout<<*s<<endl;
}
int main()
{
string str;
f2(&f1(str));
}
Run Code Online (Sandbox Code Playgroud)
但是这段代码没有编译.
我的想法是:f1按值返回所以它创建临时,我正在接收地址并传递给f2.
现在请解释一下我在想错的地方?
我有两个简单的表:
CREATE TABLE cat_urls (
Id int(11) NOT NULL AUTO_INCREMENT,
SIL_Id int(11) NOT NULL,
SiteId int(11) NOT NULL,
AsCatId int(11) DEFAULT NULL,
Href varchar(2048) NOT NULL,
ReferrerHref varchar(2048) NOT NULL DEFAULT '',
AddedOn datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
GroupId int(11) DEFAULT NULL,
PRIMARY KEY (Id),
INDEX SIL (SIL_Id, AsCatId)
)
CREATE TABLE products (
Id int(11) NOT NULL AUTO_INCREMENT,
CatUrlId int(11) NOT NULL,
Href varchar(2048) NOT NULL,
SiteIdentity varchar(2048) NOT NULL,
Price decimal(12, 2) NOT NULL,
IsAvailable bit(1) NOT NULL, …Run Code Online (Sandbox Code Playgroud) 我试过多次这样编码:
struct Foo
{
double const& f;
Foo(double const& fx) : f(fx)
{
printf("%f %f\n", fx, this->f); // 125 125
}
double GetF() const
{
return f;
}
};
int main()
{
Foo p(123.0 + 2.0);
printf("%f\n", p.GetF()); // 0
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但它根本不会崩溃。我还使用valgrind来测试程序,但没有出现错误或警告。所以,我假设编译器自动生成了一个代码,将引用指向另一个隐藏变量。但我真的不确定。
我搜索堆栈溢出,人们说修改临时对象是愚蠢的,因此不允许将临时对象绑定到非常量左值引用,就像您不能将临时对象传递给具有非常量左值引用的函数一样。
那么为什么允许临时对象调用有可能修改对象并做“愚蠢”事情的非常量成员函数呢?你可能会说,“哈,这是允许的,因为我们想为程序员提供一些灵活性,让他们做一些实际上并不那么愚蠢的“愚蠢”的事情”,这就是我很难买的原因,因为如果我买这个借口,我认为“将临时绑定到非常量左值引用”可以使用相同的原因来证明是合理的。
谢谢!我在这里几乎找不到任何相关问题。他们只是告诉我这是一个例外,但为什么我们允许这个例外呢?
我使用 Databricks 和 Apache Spark 2.4 测试了以下查询:
%sql
<step1>
create temporary view temp_view_t
as select 1 as no, 'aaa' as str;
<step2>
insert into temp_view_t values (2,'bbb');
Run Code Online (Sandbox Code Playgroud)
然后我收到此错误消息。
SQL 语句错误: AnalysisException:不允许插入基于 RDD 的表。;; 'InsertIntoTable 项目 [1 AS no#824,aaa AS str#825],false,false +- LocalRelation [col1#831,col2#832]
我的问题是
谢谢。