请考虑以下代码段:
Map<Integer, List<Loan>> loansByDuration = loans.stream()
.collect(groupingBy(Loan::getDuration, LinkedHashMap::new, toList()));
List<Loan> previousGroup = null;
for (List<Loan> currentGroup : loansByDuration.values()) {
if (previousGroup != null) {
currentGroup.addAll(previousGroup);
}
previousGroup = currentGroup;
}
我有一个关于#include <new>
#include <iostream>
struct IDivideResult {
virtual int result() = 0;
virtual int remainder() = 0;
};
struct DivideResult : IDivideResult {
DivideResult(int result, int remainder) : result_(result), remainder_(remainder) {}
int result() override { return result_; }
int remainder() override { return remainder_; }
int result_, remainder_;
};
struct LazyDivideResult : IDivideResult {
LazyDivideResult(int dividend, int divisor) : dividend_(dividend), divisor_(divisor) {}
int result() override { return Transmogrify()->result(); }
int remainder() override { return Transmogrify()->remainder(); }
DivideResult *Transmogrify() {
int result = dividend_ / divisor_;
int remainder = dividend_ % divisor_;
return new (this) DivideResult(result, remainder);
}
int dividend_, divisor_;
};
void Print(IDivideResult *div) {
int result = div->result();
int remainder = div->remainder();
std::cout << result << " " << remainder << "\n";
}
int main() {
IDivideResult *div = new LazyDivideResult(10, 3);
Print(div);
}
函数行为的问题。
预期的行为:调用Print
的div指向result()
类的实例后,调用DivideResult
函数将调用remainder()
函数。
可能(?)的行为:在调用DivideResult::remainder()
指向result()
的指针时
vtable
中的缓存。对LazyDivideResult
的下一次调用重用了先前缓存的指向remainder()
的指针,因此调用了vtable
。
我听说虚拟表不是C ++标准的一部分。同样,对clang / gcc / msvc生成的代码进行反汇编也会产生预期的行为。
这里的问题是:是否允许编译器生成导致上述“可能的行为”的代码?有保证吗?
答案 0 :(得分:1)
这是不确定的行为。
一旦调用20170630-4072-00
,指针4072-00-20170630
就会失效,因为您已经终止了它指向的对象的生命周期。您观察到的症状是它在调用div->result()
时“成功”。
从理论上讲,一个实现可以假设您只将div
传递给remainder
,因为传递DivideResult
就是UB。